关于Java多线程的两个问题使用notify()方法

时间:2017-11-16 03:21:48

标签: java multithreading

代码:

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();
    }
}

结果:

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

代码在jdk1.7和jdk1.8中执行相同的结果。

我的问题:

  • 在线程A和线程B进入SYNCHRONIZED块并调用wait()方法之后,为什么线程C和线程D进入而不是线程A说i然后线程B说i?进入同步块的优先级是否高于刚调用wait()方法的线程?

  • 为什么调用notify()方法只是唤醒那个调用wait()方法的最新线程?就像线程C和线程D一样,互相通知并等待对方,为什么不等待任何其他线程呢?像线程A和线程B。

我认为它应该是随机的,比如

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 个答案:

答案 0 :(得分:1)

问题1:

  

在线程A和线程B之后进入SYNCHRONIZED块并调用   wait()方法,为什么线程C和线程D进入而不是线程   说我然后线程B说我?是进入同步的优先级   阻止高于刚调用wait()方法的线程?

以下是Javadoc关于等待/通知的内容:

  

唤醒的线程将无法继续直到当前   线程放弃对此对象的锁定。 被唤醒的线程会   以通常的方式与任何其他可能的线程竞争   积极竞争同步这个对象;例如,   被唤醒的线程没有可靠的特权或劣势   下一个锁定此对象的线程

这意味着当线程B调用notify并且线程A需要与在同步块开始时等待的线程C和D竞争时,线程A将不能保证继续。在您的情况下,实现只优先考虑线程C和D.这就是你看到这个输出的原因:

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

问题2:

  

为什么调用notify()方法只是唤醒调用的最新线程   wait()方法?就像线程C和线程D一样,互相通知   并等待对方,为什么不等任何其他等待线程?喜欢线程   A和线程B。

Java规范再次不保证优先级。只是从线程D调用notify唤醒线程C(等待锁定,连同线程A和B)并在打印出“说”语句后从线程C调用并休眠500ms唤醒线程D(它再次等待锁定,连同线程A和B),直到它们在循环和同步块退出时,从而首先将锁定释放到线程B,然后释放到线程A。

我跑步的示例输出:

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