wait 与 notify

Java 并发编程的艺术第2版学习笔记

原书:《Java 并发编程的艺术第2版》 | 作者:方腾飞 魏鹏 程晓明 | 2023 年 9 月 | 机械工业出版社
1.3.2 等待/通知机制 | 15 页

生产者消费者模型是一个非常经典的并发模型,其中生产者和消费者之间通过一个共享的对象进行通信。在 Java 中,可以通过 waitnotifynotifyAll 方法来实现这种通信机制。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import java.text.SimpleDateFormat;
import java.util.Date;

public class WaitNotify {
    static boolean flag = true;
    static final Object lock = new Object();

    public static void main(String[] args) {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();

        SleepUtils.second(1);

        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();

    }

    static class Wait implements Runnable {
        @Override
        public void run() {
            // 加锁,拥有 lock 的 Monitor
            synchronized (lock) {
                while (flag) {
                    try {
                        print("flag is true.", "wait");
                        // 释放 lock 的锁
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                print("flag is false", "running");
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void run() {
            // 加锁,拥有 lock 的 Monitor
            synchronized (lock) {
                print("hold lock. ", "notify");
                lock.notifyAll();
                flag = false;
                SleepUtils.second(3);
            }

            synchronized (lock) {
                print("hold lock again.", "sleep");
                SleepUtils.second(3);
            }
        }
    }

    private static void print(String say, String state) {
        System.out.println(Thread.currentThread() + " " + say + " " + state + "@ " + now());
    }

    private static String now() {
        return new SimpleDateFormat("HH:mm:ss").format(new Date());
    }

}

使用 wait()、notify() 和 notifyAll() 指南

  • 调用 wait()、notify() 和 notifyAll() 前,必须先对调用对象加锁
  • 调用 wait() 方法后,线程状态由 RUNNING 变为 WAITING,并将当前线程放置到对象的等待队列
  • 调用 notify() 或 notifyAll() 方法后,等待线程依旧不会从 wait() 返回,需要调用 notify() 或 notifyAll() 的线程释放锁之后,等待线程才有机会从 wait() 返回
  • notify() 方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而 notifyAll() 方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由 WAITING 变为 BLOCKED
  • 从 wait() 方法返回的前提是获得了调用对象的锁

wait/notify 机制依托于 synchronized 机制,其目的是确保等待线程从 wait() 方法返回时能够感知到通知线程对共享变量的修改。

使用模板

wait 模板

1
2
3
4
5
6
synchronized (lock) {
    while (condition) {
        lock.wait();
    }
    // do something
}

notify 模板

1
2
3
4
synchronized (lock) {
    // change condition
    lock.notifyAll();
}
comments powered by Disqus