Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call to Java Object's wait() breaks thread synchronization

public class Main2 {
    public static void main(String[] args) {
        new Test2().start();
        new Test2().start();
    }
}

class Test2 extends Thread {
    @Override
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}

As the actual result of running the test: begin wait, begin wait, two times from the two threads. Contrast to the expected result: begin wait, only one time from one of the two threads because wait() is called inside the synchronized run() method. Why could call to Object's wait() break thread synchronization?

Thans a lot!


    public class Main3 {

    public static void main(String[] args) {
        Test3 t = new Test3();
        new Thread(t).start();
        new Thread(t).start();
    }
}

class Test3 implements Runnable {
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}

@akf & @Sean Owen

Thanks for your replies. Sorry for my mistake, now i modified the code to place the synchronization on the same object's run(), the result remained: begin wait, begin wait, two times.

@akf

wait will release the lock that synchronize has grabbed, and will be re-gotten once the thread is notified.

Could you elaborate a little bit?

like image 763
sof Avatar asked Jun 29 '10 12:06

sof


People also ask

What happens when we call wait method in Java?

In java, synchronized methods and blocks allow only one thread to acquire the lock on a resource at a time. So, when wait() method is called by a thread, then it gives up the lock on that resource and goes to sleep until some other thread enters the same monitor and invokes the notify() or notifyAll() method.

Why must wait () method be called from the synchronized block in Java?

Note also that wait() forces the thread to release its lock. This means that it must own the lock of an object before calling the wait() method of that (same) object. Hence the thread must be in one of the object's synchronized methods or synchronized block before calling wait().

Is it possible to call the wait () method in a non synchronized block?

We all know that in order to invoke Object. wait() , this call must be placed in synchronized block, otherwise an IllegalMonitorStateException is thrown.

What will happen if wait () is called from message method?

To summarize it, wait() method tells the current thread (thread which is executing code inside a synchronized method or block) to give up monitor.


2 Answers

  1. The object that you are synchronizing on in this example is not the class, but the instance, so each new Test2 object would be synchronizing on a different monitor.
  2. The method you might be looking for here is sleep, not wait. wait will release the lock that synchronized has grabbed, and will be re-gotten once the thread is notified.

Note that for your test to work correctly, you will need to lock on a common object. If you want to see wait in action, I have thrown together a simple app that will pop up a frame with a "Notify" button. Two threads will be started that wait on a common object and are in turn notified when the button is pressed.

public static void main(String[] args)
{
    final Object lock = new Object(); 
    
    final JFrame frame = new JFrame("Notify Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton button = new JButton("Notify");
    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent evt) {
            synchronized(lock) {
                lock.notify();
            }
        }
    });
    frame.add(button);
    
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            frame.setVisible( true );
        }
    });

    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("1. starting");
                    lock.wait();
                    System.out.println("1. step 1");
                    lock.wait();
                    System.out.println("1. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();
    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("2. starting");
                    lock.wait();
                    System.out.println("2. step 1");
                    lock.wait();
                    System.out.println("2. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();

}

For a simple explanation of wait, the JavaDoc is always a good place to start:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

like image 138
akf Avatar answered Oct 01 '22 00:10

akf


You have two different Test2 objects. Synchronized methods lock on the object. They are not acquiring the same lock, so no it should print twice.

like image 22
Sean Owen Avatar answered Sep 30 '22 22:09

Sean Owen