views:

152

answers:

5
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!

+2  A: 

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.

Sean Owen
+9  A: 
  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.

akf
Thanks for the example and javadoc reference!
sof
Might be good to note that the choice of which thread to wake up is arbitrary. A nice implementation will be fair and will notify threads in the order they called wait(), but that's not required. So the only constraint is that `[N]. step 1` happens before `[N]. step 2`, where N is consistently 1 or 2.
Mark Peters
@Mark Peters, that is a good point to make - though it might not seem to be arbitrary (ie, empirical evidence might try to convince you that it is ordered), there is no guarantee.
akf
A: 
    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?

sof
@sof, this is not a forum. While you are able to answer your own question, that is a rare occurrence as most of the time you will get an answer from another SO contributor before you discover one on your own. If you needed to clarify your question, you can edit it.
Tim Bender
>this is not a forumic
sof
@Tim Bender, for my first answer it should better be edited on the orignal question, i'm afraid that 2nd answer would be deemed genuine...
sof
+1  A: 

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

Antonio
A: 

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

sof