Reputation: 3756
I currently have this run method that I would like 3 seperate threads to access and wait for another thread to notify.
public void run(){
try {
System.out.println(this.name + " waits on the table...");
/// waits for agent to signal that new ingredients have been passed out
wait();
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
System.out.println(this.name + " stops waiting and checks the table...");
checkTable();
}
Currently this throws a java.lang.IllegalMonitorStateException
which can be solved by using synchroize on the method. The problem is that when I use synchroize the first thread will wait and the other two threads can't do anything since the first thread has a lock on the method. So my question is how can i make it so that three separate threads can access this method and wait at the same time?
Upvotes: 1
Views: 208
Reputation: 14873
To use wait()
you have to own the monitor.
You acquire the ownership by using synchronize
.
In you case synchronize(this)
.
But to block 3 threads and release them from a 4th, you may use java.util.concurrent.CyclicBarrier
or a java.util.concurrent.CountDownLatch
as mentioned by Perception
Here is a version with CyclicBarrier:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class RendezVous extends Thread {
private final CyclicBarrier _barrier;
RendezVous( String name, CyclicBarrier barrier ) {
super( name );
_barrier = barrier;
setDaemon( true );
start();
}
@Override public void run() {
System.out.println( getName() + " waits for counterparts..." );
try { _barrier.await(); }
catch( InterruptedException | BrokenBarrierException x ) {
x.printStackTrace(); }
System.out.println( getName() + " has reached its rendez-vous!");
}
public static void main( String[] args ) throws InterruptedException {
CyclicBarrier barrier = new CyclicBarrier( 4 );
new RendezVous( "Rdvz 1", barrier ); Thread.sleep( 1000L );
new RendezVous( "Rdvz 2", barrier ); Thread.sleep( 1000L );
new RendezVous( "Rdvz 3", barrier ); Thread.sleep( 1000L );
new RendezVous( "Rdvz 4", barrier ); Thread.sleep( 10000L );
}
}
Output:
Rdvz 1 waits for counterparts...
Rdvz 2 waits for counterparts...
Rdvz 3 waits for counterparts...
Rdvz 4 waits for counterparts...
Rdvz 4 has reached its rendez-vous!
Rdvz 1 has reached its rendez-vous!
Rdvz 2 has reached its rendez-vous!
Rdvz 3 has reached its rendez-vous!
And a version with CountDownLatch:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo extends Thread {
private final CountDownLatch _cdl;
CountDownLatchDemo( String name, CountDownLatch cdl ) {
super( name );
_cdl = cdl;
setDaemon( true );
start();
}
@Override public void run() {
System.out.println( getName() + " waits for counterparts..." );
try {
_cdl.countDown();
_cdl.await();
}
catch( InterruptedException x ) {
x.printStackTrace(); }
System.out.println( getName() + " has reached its rendez-vous!");
}
public static void main( String[] args ) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch( 4 );
new CountDownLatchDemo( "Rdvz 1", cdl ); Thread.sleep( 1000L );
new CountDownLatchDemo( "Rdvz 2", cdl ); Thread.sleep( 1000L );
new CountDownLatchDemo( "Rdvz 3", cdl ); Thread.sleep( 1000L );
new CountDownLatchDemo( "Rdvz 4", cdl ); Thread.sleep( 10000L );
}
}
Outputs:
Rdvz 1 waits for counterparts...
Rdvz 2 waits for counterparts...
Rdvz 3 waits for counterparts...
Rdvz 4 waits for counterparts...
Rdvz 4 has reached its rendez-vous!
Rdvz 1 has reached its rendez-vous!
Rdvz 2 has reached its rendez-vous!
Rdvz 3 has reached its rendez-vous!
Upvotes: 3
Reputation: 136112
When the first thread goes to wait it releases the lock. So other threads can acquire the lock
Upvotes: 0