Waiting for Java. Topic does not resume after notification.

I have a program below that has 2 threads T1 and T2. T1 starts first and goes into standby state. T2 triggers a notification. Why doesn't thread T1 resume and print "Thread-0 is awakening"

public class WaitNotifyTest{
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    try {
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + " is running");
                        notify();
                        System.out.println(Thread.currentThread().getName() + " notifying");
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

      

The exit goes like

Thread-0 is running
Thread-1 is running
Thread-1 notifying

      

Note after this output my program does not end / end. Can someone please explain why my program is not ending.

0


source to share


6 answers


There are two problems in your code 1. You have to use the same object for communication between the thread. 2. Wait and report at the same facility where you made the lock.



public class WaitNotifyTest{


    public static void main(String[] args) {
        Object lock=new Object(); 
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        System.out.println(Thread.currentThread().getName() + " is running");
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " is waken up");
                    }
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        try {
                            Thread.sleep(3000);
                            System.out.println(Thread.currentThread().getName() + " is running");
                            lock.notify();
                            System.out.println(Thread.currentThread().getName() + " notifying");
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            });
            t1.start();
            t2.start();
        }
    }

      

+2


source


I think it has something to do with what is being synchronized (this)

used for blocking.

In t1, this will refer to the anonymous class object created there.



In t2, this will refer to an Object of another anonymous class created there. In simple terms, both refer to different objects.

To work wait-notify

you must have a lock on the same object.

+1


source


The problem is that you are not syncing the same object. Try printing this

on each of the threads to check. Then, try to synchronize the same object, call wait

and notify

this lock (otherwise you will not get the correct answer).

   public class WaitNotifyTest{
    public static void main(String[] args) {
        Integer someObject = 2;
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 this = " + this);
                synchronized (someObject) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        someObject.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t2 this = " + this);
                synchronized (someObject) {
                    try {
                        Thread.sleep(3000);
                        System.out.println(Thread.currentThread().getName() + " is running");
                        someObject.notify();
                        System.out.println(Thread.currentThread().getName() + " notifying");
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

      

+1


source


You are not using wait

it notify

correctly.

You have to synchronize the same object so the threads can wait - notify each other. You can share the object among them and cause wait

and notify

with the synchronized block, using the same total Object

as the monitor. Below is the problem:

public static void main(String[] args) {
    Object obj = new Object();

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + " is running");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " is waken up");
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (obj) {
                try {
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + " is running");
                    obj.notify();
                    System.out.println(Thread.currentThread().getName() + " notifying");
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }
    });
    t1.start();
    t2.start();
}

      

Note that synchronized (this)

now synchronized (obj)

, and wait wait

and notify

not obj.wait()

and obj.notify()

.

+1


source


I agree with the other answers that you sync with the wrong object.

I suggest thinking in monitors. Monitors are objects that restrict concurrent access in order to maintain an internally consistent state. So the sync is explicitly provided by the monitor and is not propagated all over the place in the same thread. Threads do not have to sync with each other, they should be in sync with the resource they are trying to access.

public class Main {


    private static class Monitor {

        public synchronized void operation1() {
            System.out.println(Thread.currentThread().getName() + " is running");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " is waken up");
        }


        public synchronized void operation2() {
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() + " is running");
                notify();
                System.out.println(Thread.currentThread().getName() + " notifying");
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }

    }


    public static void main(String[] args) {

        Monitor monitor = new Monitor();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation1();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation2();
            }
        });

        t1.start();
        t2.start();

    }

}

      

+1


source


In addition to the fact (mentioned by others) that you are blocking different objects, you have another problem in your code. You use Thread.sleep

to make sure the waiting thread starts waiting before other calls notify

, but you still have no indication that it won't happen the other way around, forcing the waiting thread to wait forever.

You should also use some "condition variable" in the while loop to be safe.

Read the oracle docs for examples and further explanations.

+1


source







All Articles