线程等待通知机制

2017-04-17  本文已影响14人  金馆长说

机制的由来

一 个 线 程 修 改 了 一 个 对 象 的 值, 而 另 一 个 线 程 感 知 到 了 变 化, 然 后 进 行 相 应 的 操 作, 整 个 过 程 开 始 于 一 个 线 程, 而 最 终 执 行 又 是 另 一 个 线 程。 前 者 是 生 产 者, 后 者 就 是 消 费 者, 这 种 模 式 隔 离 了“ 做 什 么”( what) 和“ 怎 么 做”( How), 在 功 能 层 面 上 实 现 了 解 耦, 体 系 结 构 上 具 备 了 良 好 的 伸 缩 性, 但 是 在 Java 语 言 中 如 何 实 现 类 似 的 功 能 呢?

运行机制

等 待/ 通 知 机 制, 是 指 一 个 线 程 A 调 用 了 对 象 O 的 wait() 方 法 进 入 等 待 状 态, 而 另 一 个 线 程 B 调 用 了 对 象 O 的 notify() 或 者 notifyAll() 方 法, 线 程 A 收 到 通 知 后 从 对 象 O 的 wait() 方 法 返 回, 进 而 执 行 后 续 操 作。 上 述 两 个 线 程 通 过 对 象 O 来 完 成 交 互, 而 对 象 上 的 wait() 和 notify/ notifyAll() 的 关 系 就 如 同 开 关 信 号 一 样, 用 来 完 成 等 待 方 和 通 知 方 之 间 的 交 互 工 作。

主要方法

image
public synchronized void testRun() {
        System.out.println("执行 " + Thread.currentThread().getName());
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "执行结束");
    }


 public static void main(String[] args) throws InterruptedException {

        MainClass4 class4 = new MainClass4();

        //A线程中进入等待
        new Thread(new Runnable() {
                @Override
                public void run() {
                    class4.testRun();
                }
         }).start();
       
        Thread.sleep(300);

        //B线程中唤醒
        synchronized (class4) {
            class4.notify();
        }
    }

打印
执行 Thread-0
Thread-0执行结束

唤醒全部
notify只会唤醒待会此对象的线程,但是notifyAll会唤醒全部等待此对象的线程。

public static void main(String[] args) throws InterruptedException {

        MainClass4 class4 = new MainClass4();

        for (int i = 0; i < 4; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    class4.testRun();
                }
            }).start();
        }
        Thread.sleep(300);
        synchronized (class4) {
            class4.notify();
        }

        System.out.println("notifyAll");
        synchronized (class4){
            class4.notifyAll();
        }
    }

输出
执行 Thread-0
执行 Thread-3
执行 Thread-2
执行 Thread-1
notifyAll
Thread-0执行结束
Thread-1执行结束
Thread-2执行结束
Thread-3执行结束

等待通知机制注意事项

  1. 调用必须在同步下进行
    可以看到代码中调用wait()和nofity、nofityAll的地方都加入了synchronized同步关键字,说明等待通知的调动必须在同步下进行。

  2. 等待和通知调用必须在不同线程
    代码中wait的地方是在一个子线程,notify的地方是在main线程,它们不是在一个线程的,这也满足之前说的作用于不同线程直接的通信

  3. 必须是同一把锁
    代码中的的synchronized用的都是class4对象的锁,等待通知机制如果不是同一把锁会报监视器错误

Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at MainClass4.main(MainClass4.java:20)
  1. 必须是同一个对象
    等待的是那个对象,唤醒的就是那个对象
上一篇 下一篇

猜你喜欢

热点阅读