Reputation: 2030
There is a singleton class that n threads can access.
Each thread loads the instance of this class and invoke a method from this class in a loop.
I must control the flow of the execution so every thread can invoke the method one and pause, only after all thread invoked the method once the must resume their work. Threads can call method in any order, just all of them have to execute method once before moving the loop.
This what I tried to do:
In thread:
while ( some condition){
ObjectType obj = theSingleton.getInstance().getSharedObject();
obj.SomeMethod(threadID);
if (obj.waitisneeded())
synchronized (obj ) {
obj.wait();
}
}
what I did in SomeMethod:
public synchronized void SomeMethod(String threadID) {
hashMap.put(threadID,true);
some job here
}
and in waitisneeded:
public synchronized boolean waitisneeded(){
{
Iterator iter = hashMap.entrySet().iterator();
boolean alldone = false;
while (iter.hasNext()) {
Map.Entry me = (Map.Entry) iter.next();
String key = me.getKey().toString();
alldone = (Boolean)me.getValue();
if(!alldone) {
return false;
}
}
//set all values to false
iter = hashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry me = (Map.Entry) iter.next();
String key = me.getKey().toString();
me.setValue(false);
}
this.notifyAll();
return true;
Running this got me unexpected results and deadlocks.
How can I fix it?
Note: I can't change how the thread is created, I can only change those methods!!! (plus the while loop in the thread where wait is)
Upvotes: 2
Views: 981
Reputation: 21409
This is a typical multithreading situation called Rendez-Vous (a french word meaning "appointment"). Basically your N
threads will have an appointment and should all wait at a point until all of them reach it. As @Bruno mentioned, you can use a CyclicBarrier
object to manage the situation. In case your scenario is run only once then you could also use a CountDownLatch
.
Here is how you can achieve this:
static final CountDownLatch rendezVousPoint = new CountDownLacth(numberOfThreads);
//Every thread does the following right before waiting on the rendez vous point
rendezVousPoint.countDown();
rendezVousPoint.await();
In this situation, every thread will block on await()
method until the last thread arrives and releases all of them (rendezVousPoint
count reaches 0)
Upvotes: 0
Reputation: 37822
If you know the number of threads, you can use a CyclicBarrier
:
static final CyclicBarrier barrier = new CyclicBarrier(numberOfThreads);
Then, at the point in which you want to make all threads wait for the others, you call:
barrier.await();
If there's a thread that has not yet arrived at that line, the thread calling await()
will block. Once all the threads arrive there and call await()
, they will all resume.
Every time you must build some synchronization mechanism, be sure to check the package java.util.concurrent. There are lots of wonderful classes over there, created by experts. Most of the time you won't need something custom, and if you do, there are some classes in the same package that will make it almost unecessary to use wait/notify directly -- and, believe me, you want to avoid using these methods directly; as you can see, you can very easily get yourself into a deadlock!
Upvotes: 2