1
votes

the code:

public class NotifyAndWaitTest2 implements Runnable {
    public int i = 0;
    public Object lock;
    public SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");

    public NotifyAndWaitTest2(Object o) {
        this.lock = o;
    }

    @Override
    public void run() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " enter the SYNCHRONIZED block --- "+ sdf.format(new Date()));
            try {
                while (i < 9) {
                    Thread.sleep(500);
                    lock.notify();
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " say:" + i++ + " --- " + sdf.format(new Date()));
                }
                lock.notify();
                return;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();
        NotifyAndWaitTest2 test = new NotifyAndWaitTest2(lock);
        Thread t1 = new Thread(test,"Thread A");
        Thread t2 = new Thread(test,"Thread B");
        Thread t3 = new Thread(test,"Thread C");
        Thread t4 = new Thread(test,"Thread D");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

the result:

Thread A enter the SYNCHRONIZED block --- 10:47:07.242
Thread B enter the SYNCHRONIZED block --- 10:47:07.743
Thread C enter the SYNCHRONIZED block --- 10:47:08.243
Thread D enter the SYNCHRONIZED block --- 10:47:08.743
Thread C say:0 --- 10:47:09.243
Thread D say:1 --- 10:47:09.744
Thread C say:2 --- 10:47:10.244
Thread D say:3 --- 10:47:10.744
Thread C say:4 --- 10:47:11.245
Thread D say:5 --- 10:47:11.745
Thread C say:6 --- 10:47:12.246
Thread D say:7 --- 10:47:12.746
Thread C say:8 --- 10:47:13.247
Thread D say:9 --- 10:47:13.247
Thread B say:10 --- 10:47:13.247
Thread A say:11 --- 10:47:13.247

The code executes the same result in both jdk1.7 and jdk1.8.

my problem:

  • After thread A and thread B enter SYNCHRONIZED block and call the wait() method, why is thread C and thread D entering instead of thread A say i and then thread B say i? Is the priority of entering the sync block higher than the thread that just called wait() method?

  • Why called notify() method just wake up the lastest thread that called wait() method? just like the thread C and thread D, notify each other and wait for each other, why not any other waiting thread? like thread A and thread B.

I think it should be random, like

Thread A enter the SYNCHRONIZED block
Thread B enter the SYNCHRONIZED block
Thread A say:0
Thread C enter the SYNCHRONIZED block
Thread B say:1
Thread A say:2
Thread D enter the SYNCHRONIZED block
Thread B say:3
Thread C say:4
1
What is the expected result?Evgeniy Dorofeev
@EvgeniyDorofeev I re-edited the questionPriestM

1 Answers

1
votes

Question 1:

After thread A and thread B enter SYNCHRONIZED block and call the wait() method, why is thread C and thread D entering instead of thread A say i and then thread B say i? Is the priority of entering the sync block higher than the thread that just called wait() method?

Here is what Javadoc says about wait/notify:

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

What this means is that Thread A will not be guaranteed to proceed when Thread B calls notify and Thread A will need to compete with Thread C and D that are waiting at the start of synchronization block. The implementation just gives priority to Thread C and D in your case. That's why you see this output:

Thread A enter the SYNCHRONIZED block --- 10:47:07.242
Thread B enter the SYNCHRONIZED block --- 10:47:07.743
Thread C enter the SYNCHRONIZED block --- 10:47:08.243
Thread D enter the SYNCHRONIZED block --- 10:47:08.743

Question 2:

Why called notify() method just wake up the lastest thread that called wait() method? just like the thread C and thread D, notify each other and wait for each other, why not any other waiting thread? like thread A and thread B.

Again the Java spec does not guarantee the priority. It just happens that the call to notify from Thread D wakes up Thread C (which is waiting for lock, along with Thread A and B) and call from Thread C after it prints "say" statement and sleeps for 500ms wakes up Thread D (which is again waiting for lock, along with Thread A and B) until they exit while loop and synchronization block and thus releasing the lock first to Thread B and then to thread A.

Sample output from my run:

Thread A enter the SYNCHRONIZED block --- 09:35:59.836
Thread D enter the SYNCHRONIZED block --- 09:36:00.336
Thread C enter the SYNCHRONIZED block --- 09:36:00.836
Thread B enter the SYNCHRONIZED block --- 09:36:01.336
Thread C say:0 --- 09:36:01.836
Thread B say:1 --- 09:36:02.337
Thread C say:2 --- 09:36:02.837
Thread B say:3 --- 09:36:03.337
Thread C say:4 --- 09:36:03.837
Thread B say:5 --- 09:36:04.337
Thread C say:6 --- 09:36:04.837
Thread B say:7 --- 09:36:05.337
Thread C say:8 --- 09:36:05.837
Thread B say:9 --- 09:36:05.837
Thread D say:10 --- 09:36:05.837
Thread A say:11 --- 09:36:05.838