Java 多线程编程之:notify 和 wait 用法

发布时间:2019-11-17 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java 多线程编程之:notify 和 wait 用法脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

最近看帖子,发现一道面试题:

启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4,5…100@H_777_4@

题目要求用 Java 的 wait + notify 机制来实现,重点考察对于多线程可见性的理解。

waIT 和 notify 简介

wait 和 notify 均为 Object 的方法:

  • Object.wait() —— 暂停一个线程
  • Object.notify() —— 唤醒一个线程

从以上的定义中,我们可以了解到以下事实:

  • 想要使用这两个方法,我们需要先有一个对象 Object。
  • 在多个线程之间,我们可以通过调用同一个对象wait()notify()来实现不同的线程间的可见。

对象控制权(monitor)

在使用 wait 和 notify 之前,我们需要先了解对象的控制权(monitor)。在 Java 中任何一个时刻,对象的控制权只能被一个线程拥有。如何理解控制权呢?请先看下面的简单代码:

public class Threadtest {     public static void main(String[] args) {         Object object = new Object();         new Thread(new Runnable() {             @override             public void run() {                 try {                     object.wait();                 } catch (InterruptedException e) {                     e.PRintStackTrace();                 }             }         }).start();     } }

直接执行,我们将会得到以下异常:

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException     at java.lang.Object.wait(Native Method)     at java.lang.Object.wait(Object.java:502)     at com.xiangyu.demo.ThreadTest$1.run(ThreadTest.java:10)     at java.lang.Thread.run(Thread.java:748)

出错的代码在:object.wait();。这里我们需要了解以下事实:

  • 无论是执行对象的 wait、notify 还是 notifyAll 方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
  • 如果在没有控制权的线程里执行对象的以上三种方法,就会报 java.lang.IllegalMonitorStateException 异常。
  • JVM 基于多线程,默认情况下不能保证运行时线程的时序性

在上面的示例代码中,我们 new 了一个 Thread,但是对象 object 的控制权仍在主线程里。所以会报 java.lang.IllegalMonitorStateException 。

我们可以通过同步锁来获得对象控制权,例如:synchronized 代码块。对以上的示例代码做改造:

public class ThreadTest {     public static void main(String[] args) {         Object object = new Object();         new Thread(new Runnable() {             @Override             public void run() {                 synchronized (object){ // 修改处                     try {                         object.wait();                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }             }         }).start();     } }

再次执行,代码不再报错。

我们可以得到以下结论:

  • 调用对象的wait()notify()方法,需要先取得对象的控制权
  • 可以使用synchronized (object)来取得对于 object 对象的控制权

解题

了解了对象控制权之后,我们就可以正常地使用 notify 和 wait 了,下面给出我的解题方法,供参考。

public class ThreadTest {     private final Object flag = new Object();      public static void main(String[] args) {         ThreadTest threadTest = new ThreadTest();         ThreadA threadA = threadTest.new ThreadA();         threadA.start();         ThreadB threadB = threadTest.new ThreadB();         threadB.start();     }      class ThreadA extends Thread {         @Override         public void run() {             synchronized (flag) {                 for (int i = 0; i <= 100; i += 2) {                     flag.notify();                     System.out.println(i);                     try {                         flag.wait();                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }             }          }     }      class ThreadB extends Thread {         @Override         public void run() {             synchronized (flag) {                 for (int i = 1; i < 100; i += 2) {                     flag.notify();                     System.out.println(i);                     try {                         flag.wait();                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }             }         }     } }

发散:notify()notifyAll()

这两个方法均为 native 方法,在JDK 1.8 中的关于notify()的JavaDoc如下:

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened.

译为:

唤醒此 object 控制权下的一个处于 wait 状态的线程。若有多个线程处于此 object 控制权下的 wait 状态,只有一个会被唤醒。

也就是说,如果有多个线程在 wait 状态,我们并不知道哪个线程会被唤醒。

在JDK 1.8 中的关于notifyAll()的JavaDoc如下:

Wakes up all threads that are waiting on this object's monitor.

译为:

唤醒所有处于此 object 控制权下的 wait 状态的线程。

所以,我们需要根据实际的业务场景来考虑如何使用。

脚本宝典总结

以上是脚本宝典为你收集整理的Java 多线程编程之:notify 和 wait 用法全部内容,希望文章能够帮你解决Java 多线程编程之:notify 和 wait 用法所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。