3
public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

Here It is showing ouptut:-

i=0in t1 
i=1in t4 
Thread-0is running 
Thread-1is notifying 
notified 

One last line should also be printed in output i.e; "Thread-0 is waken up". Why after printing "notified" it doesn't loose lock to thread "t1 run() method " and continue with the code after wait() in t1 . i.e it should print "Thread-0 is waken up" after printing "notified".

Pradeep Singh
  • 1,094
  • 1
  • 9
  • 24
aditya soni
  • 75
  • 10

4 Answers4

2

Your synchronized blocks have "no" effect.

Your synchronized(this) just gets the lock for the Runnable instance where you also implement the run method.

Your Thread t1 will never be notified, it waits for the Runnable where you use the wait() method to get notified. The only object that holds a reference to this Runnable is the Thread Object t1 and that will (usually) not call notify() or notifyAll() on that Runnable.

I'm using an int[] for storing the int value as well as for holding the lock / monitor. The solution is only to show you how you could do it, not meant that this is good practice to do it this way.

I'd recommend to read a good tutorial about how synchronized in Java works.

I've modified you example so that it works as you expect.

public class NotifyAndWaitExample2 {
    private static int[] i = {0};

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    if (i[0] <= 0) {
                        System.out.println("i=" + i[0] + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");
                        try {
                            i.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    i[0]++;
                    System.out.println("i=" + i[0] + "in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        i.notifyAll();
                        System.out.println("notifying");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}
andih
  • 5,570
  • 3
  • 26
  • 36
  • calling notify() is enough to release the lock from thread t4 ? – aditya soni Jun 09 '17 at 09:31
  • @adityasoni `notify()` is enough to wake up `t1`. It does not release any locks. The lock `t4` holds is released when `t4` leaves the `synchronized` block. – andih Jun 09 '17 at 09:35
  • so when lock is holded by thread t4 and after calling notify() it wakes up thread t1, and obviously it much release the lock also then only another thread takes the lock and executes its subsequent task? – aditya soni Jun 09 '17 at 10:40
  • Not sure if I understand the question. After releasing the lock another thread can take the lock and perform it's task. You may have a look at https://stackoverflow.com/a/6221775/1317117 – andih Jun 09 '17 at 10:47
  • my question is Does notify() release the lock from calling thread? – aditya soni Jun 09 '17 at 10:54
  • `notify()` does not release any locks see https://stackoverflow.com/questions/5999193/does-notify-notifyall-release-the-lock-being-held – andih Jun 09 '17 at 10:58
  • yes, as per Javadoc notify() won't release the lock then in my code how the lock has been released by thread t4 and gone to thread t1 ? – aditya soni Jun 09 '17 at 11:04
  • `t4` releases the lock when leaving the synchronized block. `t1` must regain the lock after `wait`. If you want to know more about it you may have a look at https://stackoverflow.com/questions/13249835/java-does-wait-release-lock-from-synchronized-block – andih Jun 09 '17 at 11:16
  • thanks for your efforts , i got my questions answered. – aditya soni Jun 09 '17 at 11:45
1

you are locking in two different objects. in your example, "this" refers to each of the runnable instances. Besides that, variable "i" must be volatile (otherwise, different threads won't see the latest changes)

see below:

public class NotifyAndWaitExample {

    private volatile int i = 0;
    private Object lock1 = new Object();

    public static void main(String[] args) {
        NotifyAndWaitExample notifyAndWaitExample = new NotifyAndWaitExample();
        notifyAndWaitExample.execute();
    }

    private void execute() {


        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    if (i <= 0) {
                        System.out.println("i= " + i + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");

                        try {
                            lock1.wait();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });

        Thread t4 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    i++;
                    System.out.println("i= " + i + " in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        lock1.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });


        t1.start();
        t4.start();
    }

}
Jose Zevallos
  • 685
  • 4
  • 3
  • this keyword also point to current object that is shared by two thread, what is the problem in using that? – aditya soni Jun 09 '17 at 09:41
  • in your example, the "this" keyword made reference to two different objects (each of the runnable objects). when you want to achieve mutual exclusion, you have to synchronize all threads on the same object. that is why in my example I'm using "lock1". and both threads must synchronize in that object – Jose Zevallos Jun 09 '17 at 09:54
  • thanks i got the answer for "why we can't use this here" ? but still stuck for the question "does calling notify release the lock? – aditya soni Jun 09 '17 at 10:46
  • ok. good. calling "notify" will wake up a thread that is waiting for this lock to be released. but the lock will be released only when you finish executing the synchronized block. After exiting the synchronized block, the recently awaked thread will grab the lock and then it can continue. (therefore, it is guaranteed that only one thread at a time can execute a synchronized block that is guarded by a common lock) – Jose Zevallos Jun 09 '17 at 10:57
  • okay i got your point, as in my code when the synchronized block will get complete it release its lock, but in the case of a infinite loop applied in the synchronization block, then what happens? – aditya soni Jun 09 '17 at 11:13
  • then, you have a deadlock. – Jose Zevallos Jun 09 '17 at 11:29
  • we can avoid it by having one more wait() in the notify() synchronized block, correct me if i am wrong? – aditya soni Jun 09 '17 at 11:43
  • you cannot avoid a deadlock if after notifying a waiting thread, your current thread enters an infinite loop (because the lock will never be released). This is why it is difficult to write correct multi-threaded code. – Jose Zevallos Jun 09 '17 at 11:48
1
public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Object lock = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        lock.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}
gati sahu
  • 2,576
  • 2
  • 10
  • 16
1

Your current problem ist that you synchronize over the wrong (different) object(s). As you say "synchronized(this)" in your code "this" is the current thread instance. As you have two of them synchronization will not take place.

I really suggest to think in monitors. A monitor is a ressource wrapper that restricts concurrent access in a way to preserve internal state consistency. I reformulated your code to use a monitor.

public class NotifyAndWaitExample2 {

    private static class Monitor {

        // Resource
        private int i;


        public synchronized void operation1() {

            if (i <= 0) {
                System.out.println("i=" + i + "in t1");
                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() {

            i++;
            System.out.println("i=" + i + "in t4");
            System.out.println(Thread.currentThread().getName() + "is notifying");
            try {
                Thread.sleep(1000);
                notify();
                System.out.println("notified");
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                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 t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation2();
            }
        });

        t1.start();
        t4.start();

    }
}

"wait()" and "notify()" were now performed on the SAME object so the executing threads will be synchronized.

oopexpert
  • 767
  • 7
  • 12
  • One additional comment: Threads should not synchronize. They should be synchronized. – oopexpert Jun 09 '17 at 10:51
  • oh cool :).. one more question .. does notify() release the lock from the its calling thread? – aditya soni Jun 09 '17 at 10:53
  • 1
    I work on a semantic level. So the question is why should I blindly notify other waiting threads? As the code is executed by an arbitrary thread but the code belongs to the monitor the monitor code is specifiying that there are other threads explicitly known to the monitor: Maybe a management thread that has to perform a cleanup. So NO, the lock will not be released. The lock will be held as long the thread is in the monitor. But after the "client" thread exists the monitor a specific thread that is exactly known to the monitor will be the next to perform any actions neccessary. – oopexpert Jun 09 '17 at 11:13
  • notify() will put one thread that previously has called "wait()" into a state so it will enter the monitor when it is free. – oopexpert Jun 09 '17 at 11:18
  • okay now i got it , so in case of infinite loop over notify() how we can release the lock?does we have to call wait() again to release lock or is there some other construct? – aditya soni Jun 09 '17 at 11:24
  • wait() should be the contract to say: currently I will not change the resource until I will be notified again. So yes. Calling wait should release the lock. – oopexpert Jun 09 '17 at 11:30