开发者

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 synchron开发者_C百科ize has grabbed, and will be re-gotten once the thread is notified.

Could you elaborate a little bit?


  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.


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.


an simple example that can help you is this:

        public class test {
            public static void main(String[] args) {
                Prova a=new Prova();
                new Test2(a).start();
                new Test2(a).start();
            }
        }
        class Prova{
            private boolean condition;

            public void f(){

                while(condition){
                    //Thread.currentThread  Returns a reference to the currently executing thread object.
                    //Thread.getName() return name Thread
                    System.out.println(Thread.currentThread().getName()+" begin wait");
                    try{
                        wait();
                    }catch(InterruptedException c){return;}
                }       

                System.out.println(Thread.currentThread().getName()+" first to take the mutex");
                condition=true;

            }
        }
        class Test2 extends Thread {
            private Prova a;
            private static boolean condition;


            public Test2(Prova a){
                this.a=a;
            }
            @Override

             public void run() {
               synchronized(a){
                try {           
                    a.f();           
                } catch (Exception ex) {
                }
               }
            }
        }

in this case the two threads synchronize an object, the first taking the lock release message, the second one waits. in this example uses the condition variable


summary to wait/notify mechanism:

1)current thread reaches one object's synchronized code block which contains the call to wait(), it competes with other threads for the lock(the object's monitor), as winner it executes the block till the call to wait() encounters.

2)by calling wait(), current thread releases the lock to other competing threads, then halts execution, wait for notify being sent from another thread who succeeds in obtaining the lock.

JavaDoc:

A thread becomes the owner of the object's monitor in one of three ways:

•By executing a synchronized instance method of that object.

•By executing the body of a synchronized statement that synchronizes on the object.

•For objects of type Class, by executing a synchronized static method of that class.

3)another thread reaches the same object's yet another synchronized code block which contains the call to notify/notifyAll(), it competes with other threads for the lock, as winner it executes the block till finishing the call to notify/notifyAll(). It will release the lock either by call to wait() or at the end of the execution on the block.

4)upon receiving notify/notifyAll(), current thread competes for the lock, as winner the execution continues where it has halted.

simple example:

    public class Main3 {

    public static void main(String[] args) {
        Test3 t = new Test3();
        new Thread(t).start();
        new Thread(t).start();
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
        }
        t.testNotifyAll();
    }
}

class Test3 implements Runnable {

    synchronized public void run() {

        System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock");
        try {
            wait();
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock again");
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "bye wait block");

    }

    synchronized void testNotifyAll() {
        System.out.println(Thread.currentThread().getName() + ": " + "notify block got the lock");
        notifyAll();
        System.out.println(Thread.currentThread().getName() + ": " + "notify sent");
        try {
            Thread.sleep(2000);
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "bye notify block");
    }
}

output:

Thread-0(or 1): wait block got the lock

Thread-1(or 0): wait block got the lock

main: notify block got the lock

main: notify sent

main: bye notify block

Thread-0(or 1): wait block got the lock again

Thread-0(or 1): bye wait block

Thread-1(or 0): wait block got the lock again

Thread-1(or 0): bye wait block

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜