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


    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 状态的线程。

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

    原文链接:https://segmentfault.com/a/1190000018096174?utm_source=tag-newest

    参考地址:https://mp.weixin.qq.com/s/WoQtQSDygBwC_lJyOhf1EQ

  • 相关阅读:
    c++——类 继承
    Pytorch Tensor, Variable, 自动求导
    Python-OpenCV实现二值图像孔洞填充
    神经网络手写数字识别numpy实现
    神经网络反向传播公式推导
    转:Markdown语法大全
    markdown居中对齐,左对齐,右对齐
    硬编码与软编码
    转:Markdown数学公式语法
    Python if __name__=='__main__'
  • 原文地址:https://www.cnblogs.com/Tony100/p/11969695.html
Copyright © 2020-2023  润新知