I'm working on a multithreaded program where each thread calculates the GCD for two numbers, stores the numbers and GCD into a TreeMap, and prints out the TreeMap after all the threads finish. What kind of method should I use to make sure that only one thread is storing the data at the same time, and how do I use the last thread to print the TreeMap when it is ready to print?
for (int i = 0; i < myList.size(); ++i) {
for (int j = i + 1; j < myList.size(); ++j) {
modulus1 = myList.get(i);
modulus2 = myList.get(j);
pool.execute(new ThreadProcessRunnable(modulus1, modulus2, myMap));
}
}
public void run() {
ThreadProcess process = null;
try {
// Only one thread should execute the following code
for (Map.Entry<BigInteger, ArrayList<BigInteger>> entry : myMap.entrySet()) {
System.out.println("key ->" + entry.getKey() + ", value->" + entry.getValue());
}
} catch (Exception e) {
System.err.println("Exception ERROR");
}
You must use syncronize(myMap) {...} block in places where you need to guarantee single thread access to the map.
As for printing the result by the last thread, you can use a boolean flag as a signal of completeness and check it every time. Don't forget to make it volatile to let each thread see its value changes.
UPD: Brian Goetz "Java Concurrency In Practice" is a strongly recommended reading.
//Only one thread should executes the following code
synchronize{
for (Map.Entry<BigInteger, ArrayList<BigInteger>> entry : myMap.entrySet()) {
System.out.println("key ->" + entry.getKey() + ", value->" + entry.getValue());
}
}
You can use Collections.synchronizedMap to make it thread safe. And use thread.join to make sure printing is done only when all threads are dead.
Edit: Do the printing in Main thread. Just before printing, call join on all threads.
Related
I am counting votes for electronic election and I have only one party in my initial version. There will be different threads per voter and the threads will update the votes count of a given party.
I decided to use ConcurrentHashMap, but the results are not what I expected...
Map<String, Integer> voting = new ConcurrentHashMap<>();
for (int i = 0; i < 16; i++) {
new Thread(() -> {
voting.put("GERB", voting.getOrDefault("GERB", 0) + 1);
}).start();
}
for (int i = 0; i < 100; i++) {
voting.put("GERB", voting.getOrDefault("GERB", 0) + 1);
}
Thread.sleep(5000); // Waits for the threads to finish
for (String s : voting.keySet()) {
System.out.println(s + ": " + voting.get(s));
}
The result is different every time - it ranges from 114 to 116.
Isn't ConcurrentHashMap supposed to be synchronised?
Well, there's a compound action here. You get the map value given a key, increment it by one, and place it back in the map against the same key. You have to guarantee that all these statements execute atomically. But the given implementation does not impose that prerequisite. Hence you end up with a safety failure.
To fix this, you can use the atomic merge operation defined in ConcurrentHashMap. The entire method invocation is performed atomically. Here's how it looks.
Map<String, Integer> voting = new ConcurrentHashMap<>();
for (int i = 0; i < 16; i++)
new Thread(() -> {
voting.merge("GERB", 1, Integer::sum);
}).start();
for (int i = 0; i < 100; i++)
voting.merge("GERB", 1, Integer::sum);
Thread.sleep(5000); // Waits for the threads to finish
for (String s : voting.keySet())
System.out.println(s + ": " + voting.get(s));
Running this program produces the following output:
GERB: 116
Assume there are two or more threads performs
voting.put("GERB", voting.getOrDefault("GERB", 0) + 1);
what happens?
Lets say value on key "GERB" now equals 10
Thread #1 gets value voting.getOrDefault("GERB", 0). It is 10
Thread #2 gets value voting.getOrDefault("GERB", 0). It is 10
Thread #1 adds 1, now it is 11
Thread #2 adds 1, now it is 11
Thread #1 writes values 11 back to voting
Thread #2 writes values 11 back to voting
Now, although 2 threads completes, the value increased only by 1 because of concurency.
So, yes, methods of ConcurrentHashMap are synchronized. That means, when one thread executes e.g. put, another thread waits. But they do not synchronize threads outside anyhow.
If you perform several calls you have to synchronize them on your own. E.g.:
final Map<String, Integer> voting = new ConcurrentHashMap<>();
for (int i = 0; i < 16; i++) {
new Thread(() -> {
synchronized (voting) { // synchronize the whole operation over the same object
voting.put("GERB", voting.getOrDefault("GERB", 0) + 1);
}
}).start();
}
UPD
As it noted in the comments, keep in mind that synchronization over voting object does not guarantee synchronization with ConcurentHahMap's methods itself. You have to perform that synchronization for every call to voting methods if those calls can be performed concurrently. In fact, you can use any other object to synchronize (it's not required to be voting): it only needs to be the same for all the threads.
But, as it noted by #Holger, this defeats the very purpose of the ConcurentHashMap.
To utilize the atomic mechanics of ConcurentHashMap without locking the threads you can use method replace to retry the operation if the value was altered by another thread:
for (int i = 0; i < 16; i++) {
new Thread(() -> {
Integer oldValue, newValue;
do {
oldValue = voting.getOrDefault("GERB", 0);
newValue = oldValue + 1; // do some actions over the value
} while (!voting.replace("GERB", oldValue, newValue)); // repeat if the value was changed
}).start();
}
You can divide this line voting.put("GERB", voting.getOrDefault("GERB", 0) + 1); into three steps:
int temp=voting.getOrDefault("GERB",0); //1
temp++; //2
voting.put("GERB",temp); //3
Now between line1 and line3, Other thread can change the value associated with "GERB" because the method has return, there is nothing can stop other thread from changing it. So when you call voting.put("GERB",temp),you override their value which makes their update lost.
===update====
from comment
so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. Does anyone know what could happen? If I want to prove it's not thread safe how can I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen not working example? Do you have sample code?
If I have three threads accessing the hashset of string.
One adding a new string
Second removing the string
Third removing all
Is the HashSet thread safe?
public void test()
{
Set<String> test = new HashSet<>();
Thread t0= new Thread(new Runnable() {
#Override
public void run() {
while (true) {
boolean c = test.contains("test");
System.out.println("checking " + c);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
test.add("test");
System.out.println("adding");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
if (!test.isEmpty())
{
test.removeAll(test);
}
System.out.println("removing");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t0.start();
t1.start();
t2.start();
while(true) {
}
}
I have this test code and ran it and it seems working. No exceptions were thrown. I was little confused because HashSet is not thread-safe.
Whay am I missing?
From comment:
so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. does anyone know what could happen? If I want to prove it's not thread how cam I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen that not working example? do you have sample code?
The problem is that updating the Set may not be an atomic operation, especially not when the internal hash table needs to be re-sized.
If two threads are updating at the same time, you may get the simple result that one thread overrides the change by the other thread, so you lose a change. More seriously, the conflict may corrupt the internal structure of the Set.
To show this, here is a small program that causes high conflict during add of values. All values added are distinct, so they should all be added, but you will see that size of the Set is incorrect when program is done, proving that some added values got lost.
final int THREAD_COUNT = 10;
final int NUMS_TO_ADD = 100000;
Set<Integer> set = new HashSet<>();
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
final int threadNo = i;
threads[i] = new Thread() {
#Override public void run() {
for (int j = 0; j < NUMS_TO_ADD; j++)
set.add(j * THREAD_COUNT + threadNo); // all distinct values
}
};
threads[i].start();
}
for (int i = 0; i < threads.length; i++)
threads[i].join();
System.out.println("Found " + set.size() + " values, expected " + THREAD_COUNT * NUMS_TO_ADD);
Each time you run it, you will get a different result, e.g.
Found 898070 values, expected 1000000
Found 825773 values, expected 1000000
Found 731886 values, expected 1000000
Exception in thread "Thread-7" java.lang.ClassCastException: java.base/java.util.HashMap$Node cannot be cast to java.base/java.util.HashMap$TreeNode
at java.base/java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1883)
at java.base/java.util.HashMap$TreeNode.putTreeVal(HashMap.java:2063)
at java.base/java.util.HashMap.putVal(HashMap.java:638)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.add(HashSet.java:220)
at Test$1.run(Test.java:16)
Or the program simply hangs!
Thread Safe
Thread unsafe does not mean you can not use it in multi-treads or the program will throw exceptions. It means you can not always get what you want when program is executed in multi threads. See this for more.
In computer programming, thread-safe describes a program portion or
routine that can be called from multiple programming threads without
unwanted interaction between the threads.
And, you can not say an object is thread safe even if you get the expected experiment results. Because the results may vary in different environments. You should use synchronization mechanism provided by JDK.
HashSet
HashSet is not thread safe, this means:
If you write an object into it, this object may not be visible to
other threads.
If you read the set from different threads at same time, they may get different results.
If you call add first, then call removeAll, the objects in this
set may not be removed.
......
User Andreas's example is pretty clear. Since HashSet is based on HashMap's key set, you can refer this How to prove that HashMap in java is not thread-safe.
Solution
JDK provided a thread safe version set, all operations on the set need aquire a inner monitor lock first.
Set s = Collections.synchronizedSet(new HashSet(...));
I was learning multithreading in java, In the tutorial, it said removing synchronized should make the program buggy and it did, So I was just experimenting around and wrote a print line System.out.println(Thread.currentThread().getName() + " " +count);
and removed the synchronized word, and even then the program worked fine. But if only synchronized word is removed and the printline(System.out.println(Thread.currentThread().getName() + " " +count);) is not added the program is buggy ad expected.
I can't understand how adding a print line can make it synchronized.
public class intro implements Runnable {
int n=10000;
private int count = 0;
public int getCount() { return count; }
public synchronized void incrSync() { count++; }
public void run () {
for (int i=0; i<n; i++) {
incrSync();
//System.out.println(Thread.currentThread().getName() + " " +count);
}
}
public static void main(String [] args) {
intro mtc = new intro();
Thread t1 = new Thread(mtc);
Thread t2 = new Thread(mtc);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException ie) {
System.out.println(ie);
ie.printStackTrace();
}
System.out.println("count = "+ mtc.getCount());
}
}
Synchronization issues happen between threads when multiple threads attempt access to the same field at the same time.
Without the printing the run method sits in a tight loop accessing the counter almost continuously. Making multiple threads do that without synchronization is very likely to cause a fault.
By adding the printing you are changing the loop to spend most (almost all) of its time printing and only occasionally increment the count. This is much less likely to cause contention.
The code is still buggy with the printing, the only difference is that the contention will happen much less often and your test of just 1000 loops is not sufficient to demonstrate the issue. You'd probably have to run it for a few years before the threads clashed.
This is a classic demonstration of why threading issues are so difficult to find and fix. That loop (with it's print statement) could run on multiple threads for years without contention but if just one clash between threads happens then the code breaks. Imagine that happening in a heart pacemaker or a satellite or a nuclear power station!
The println method calls newline, which is a method with a synchronized-block. It is giving correct result, though it is not thread safe.
Consider T1 read count 5 and T2 read count 5 simultaneously, then race condition happen. It is giving correct result because you are using System.out.println(Thread.currentThread().getName() + " " +count); which is blocking. Increase thread number.
private void newLine() {
try {
synchronized (this) {
ensureOpen();
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
This is a test code I have created to study threads. It consist of two threads assigned to the same Runnable. They have to deduct 5 to an int, and stop if the int is not big enough to deduct 5. Thing is, thread 1 "alpha" keeps looping until it is halfway within the loop, in this case being 5. Then thread 2 "beta" starts. It is an extrange behaviour I cannont comprehend. What am I missing?
public class synconizedThread implements Runnable {
int balance = 100;
public void run() {
checkAmmount();
}
public void checkAmmount() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()
+ "checks balance: " + balance);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
withDrawAmmount();
}
}
}
public void withDrawAmmount() {
if (balance <= 0) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Balance is " + balance + " not enough");
}
else {
balance = balance - 5;
System.out.println(Thread.currentThread().getName()
+ "Whitdraws, balance left: " + balance);
}
}
public static void main(String[] args) {
Runnable myJob = new synconizedThread();
Thread alpha = new Thread(myJob);
alpha.setName("alpha");
Thread beta = new Thread(myJob);
beta.setName("beta");
alpha.start();
beta.start();
}
}
You're synchronizing the entire loop, so the first thread enters the loop, then won't give up the CPU until after the loop completes.
Instead, you probably want to synchronize each iteration of the loop, that way the threads will have a chance to alternate.
You're also synchronizing the call to sleep(), which probably isn't what you want to do. You probably want to move that outside your synchronization.
public void checkAmmount() {
for (int i = 0; i < 10; i++) {
synchronized (this) {
System.out.println(Thread.currentThread().getName()
+ "checks balance: " + balance);
withDrawAmmount();
}
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
I see two issues:
The loop is within the synchronized block. So whoever gets that lock first executes the loop. Put the synchronized inside the loop. Then a thread will release the lock at the end of an iteration, and compete for it again at the beginning of the next, and you will have concurrency. For example, make the withDrawAmount() method synchronized. (If you do that, make sure to move the println of thread ID to inside the withDrawAmount().)
Thread.sleep() does not release the lock, so it's not like that fixes the problem of the loop being inside synchronized. You should probably take every Thread.sleep() call out altogether since they're just slowing things down.
As ever, you should try to keep the critical section - the piece inside synchronized - as small as possible, for maximum concurrency. Synchronizing withDrawAmount() should be fine, especially once you get rid of those sleep() calls. If you want to have some fun and try to see if you can get even bigger throughput, take a look at java.util.conccurent.atomic.AtomicInteger
Your first thread enters the synchronized block, loops for 10 iterations and withdraws 5 at each iteration, and then leaves the synchronized block.
So when the 10 iterations are done (and the balance is thus 50), it stops running, leaves the synchronized block, allowing the second thread to run and executes its 10 iterations.
It's the synchronized keyword. You have it around the whole for loop, so whoever gets to it first gets to run the entire for loop.
Thread B can't access the variable while Thread A is using it - it's locked by A.
If you want both to deduct at the same time you should move the synchronized inside the for loop.
As far as I understand your question, your problem is that thread alpha is already halfway through his loop until thread beta starts.
The synchronized keyword blocks all other thread from accesing the synchronized object. You could put the synchronized keyword inside the loop so that each thread enters and then leaves the monitor each time
ALso, by default, threads do not necessarily get the equal cpu time. So thread alpha starts working as soon as you invoke the start() method and is already halfway through until thread "beta" is even started by the main Thread
Thread safe Map of Queues
The above question has a design implementation VERY similar to my own. I understand why it's not thread safe, but the accepted "pattern" is throwing me for a loop. I don't quite get how to implement it or what it does in relationship to the question.
boolean send = false;
System.out.println("MailCenter Size Start: " + mailBox.keySet().size());
if (parsedInput.size() == 3) {
for (String s : writers.keySet()) {
if (!s.equals(parsedInput.get(1))) {
send = true;
}
}
if (send) {
mailMessage.add(noAnsiName + ": " + parsedInput.get(2));
mailBox.putIfAbsent(parsedInput.get(1), mailMessage);
System.out.println("Current mail message is: " + mailMessage.peek());
out.println("SERVER You have sent mail to " + parsedInput.get(1) + ".");
}
System.out.println("MailCenter Size Middle: " + mailBox.keySet().size());
} else {
int loop = 0;
for (Map.Entry entry : mailBox.entrySet()) {
System.out.println(entry.getKey() + ":\t" + entry.getValue());
System.out.println("*** LOOP STATUS *** " + loop);
loop++;
}
}
I don't quite get how to implement it or what it does in relationship
to the question.
The question shows that a ConcurrentHashMap is being used. However, the variable map is being declared as a Map, so the method putIfAbsent() referenced by the accepted answer is not visible.
Map<String, ConcurrentLinkedQueue<String>> map = new ConcurrentHashMap<>();
So, in order for the answer to work, the above must be changed to declare map as a ConcurrentMap.
Now, that's a good step toward thread safety. However, just because we're using a concurrent map implementation doesn't mean a get() and subsequent put() on the map are an atomic unit of work. In other words, another thread can still change the state of the map after the current thread calls get(), but before it calls put().
The answer recommends putIfAbsent() because it ensures atomicity by wrapping the equivalent of a containsKey() call and a put() call in a synchronized block. If you also then use the return value correctly, you will have solid concurrent behavior.