Reputation: 22518
I have read carefully the Oracle documentation and I could not find a design pattern solution for my issue. I have two anonymous threads and one needs to notify the other.
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.a();
obj.b();
}
The MyClass has two different functions, each one launches an anonymous thread. The B person expects to be woken up by his wife, A.
public class MyClass{
public MyClass(){
}
public void a() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("A: I am going to sleep");
try {
Thread.sleep(1000);
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
}).start();
}
}
Unfortunately, B sleeps forever and could not be woken up by his wife, A.
Output of the program:
A: I am going to sleep
B: I am going to sleep. A, please wake me up.
A: I slept one full day. Feels great.
A: Hey B, wake up!
I understand that A and B are running in two different anonymous threads objects, so A could notify only other A (there are not other wife in the bed so the notify function is useless here).
What is the correct design pattern for this issue?
Upvotes: 0
Views: 1233
Reputation: 2444
You have two problems in your Code.
As suggested by others . You need to take the same lock for using notify and wait. You are using different Objects for waiting and notifying which is their respective thread instances. Your below code is run use MyClass.this
try { wait(); } catch (InterruptedException e) {
There is another problem with your code even if you use right locks. Which i think you try to encounter by Thread.sleep(1000) in thread A. This problem is called Missed Notifications, i.e. your threadA can complete before your threadB executes its wait() method, this will result in infinite sleep of threadB.
Solution for both the above problem is to use a latch . try CountDownLatch See below
import java.util.concurrent.CountDownLatch;
public class MyClass{
CountDownLatch latch = new CountDownLatch(1);
public MyClass(){
}
public void a() {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("A: I am going to sleep");
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
try {
latch.await();
} catch (InterruptedException e) {}
System.out.println("B: Thank you A for waking me up!");
}
}).start();
}
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.a();
obj.b();
}
}
Upvotes: 0
Reputation: 11807
To be able to wake one thread from another they need to be synchronized with a common object. For example you could use the MyClass object the threads are called from:
public void a() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("A: I am going to sleep");
synchronized(MyClass.this)
{
try {
Thread.sleep(1000);
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
MyClass.this.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
public void b() {
new Thread(new Runnable(){
@Override
public synchronized void run() {
System.out.println("B: I am going to sleep. A, please wake me up.");
synchronized(MyClass.this)
{
System.out.println("B: Thank you A for waking me up!");
}
}
}).start();
}
This will make a()
's thread acquire the lock and sleep for 1000ms. Meanwhile b()
would be called but it's thread would have to wait until a()
's thread releases the lock before it can print Thank you for waking me up
.
This would work if you always call a()
before b()
. Otherwise, if b()
acquires the lock first, it's Thank you for waking me up
would be executed before a()
sleep
.
Upvotes: 0
Reputation: 34321
Both threads need to lock using the same semaphore object.
Currently the locks in your code are on two different objects - the Runnable
created by a
has a lock on the itself and the same with b
, so when you call notifyAll
there are no object waiting for the lock to notify.
There's also a problem with the Thread.sleep
inside the synchronized block.
Change your code so that the lock obtained when the synchronized
key word is used like this:
public void a()
{
new Thread(
new Runnable()
{
@Override
public void run()
{
try
{
System.out.println("A: I am going to sleep");
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
synchronized(MyClass.this)
{
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
MyClass.this.notifyAll();
}
}
}
).start();
}
public void b()
{
new Thread(
new Runnable()
{
@Override
public void run()
{
synchronized(MyClass.this)
{
System.out.println("B: I am going to sleep. A, please wake me up.");
try
{
MyClass.this.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
}
}
).start();
}
Upvotes: 1
Reputation: 17622
The basic point is wait()
and notify()
or notifyAll()
should be called on a single object monitor to have thread synchronization. I would have done something like this
In my code the MyClass
has a()
and b()
instance method synchronized
. So the instance on which these methods get invoked will become implicit monitors. I am sharing the same instance of MyClass
(which is obj
) with 2 Runnable
implementations
public class MyClass{
public MyClass(){
}
public synchronized void a() {
System.out.println("A: I am going to sleep");
try {
Thread.sleep(5000);
wait();
System.out.println("A: I slept one full day. Feels great.");
System.out.println("A: Hey B, wake up!");
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void b() {
System.out.println("B: I am going to sleep. A, please wake me up.");
notifyAll();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B: Thank you A for waking me up!");
}
public static void main(String [] args) {
MyClass obj = new MyClass();
Thread t1 = new Thread(new RunnableImpl(obj, true));
Thread t2 = new Thread(new RunnableImpl(obj, false));
t1.start();
t2.start();
}
}
class RunnableImpl implements Runnable {
boolean callA;
MyClass obj;
public RunnableImpl(MyClass obj, boolean callA) {
this.callA = callA;
this.obj = obj;
}
@Override
public void run() {
if(callA) {
obj.a();
}
else {
obj.b();
}
}
}
Upvotes: 0
Reputation: 73558
You need to have a common object shared by the threads to call the wait()/notify() methods on. Now you're calling them on the this
object, which in both cases is their own Thread object.
Also note that you need to synchronize on the common object too, so you can't just put synchronized on your run() methods.
Upvotes: 0
Reputation: 16997
There will need to be a shared ReentrantLock between these threads, perhaps as a class variable. Thread A locks the lock first, then to go to sleep, thread B locks it. Thread A awakens thread B by unlocking the lock. You can also use a semaphore for this.
Upvotes: 0