• Object类中的线程交互,wait、notify、notifyAll


    Object对象概述

    在说这些方法之前,有一点需要先思考一下,为什么wait,notify,notifyAll这些跟线程有关的方法是封装在Object中而不线程的Thread类呢?这也是一道面试题经常问的内容。

    其实答案很简单,之前我们说过,可以把任意的对象作为锁资源进行竞争,而Object是所有类的父类,所以任意对象都可以调用wait()和notify();所以wait和notify属于Object,当然,在jdk1.5之后还出现了各种线程唤醒、阻塞的方法,包括之前提到的LockSupport中的'park',UnPark,和Condition中的Await和signal等等。

    • void notify():唤醒在此对象监视器上等待的单个线程。
    • void notifyAll():唤醒在此对象监视器上等待的所有线程。
    • void wait():导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
    • void wait(long timeout):导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
    • void wait(long timeout, int nanos):导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

    wait方法

    当一个线程调用了共享锁对象的wait方法之后,该线程就会被阻塞挂起。直到另一个线程调用了该锁对象的notify方法或者notifyAll方法,原本那个调用wait方法的线程才会被唤醒。另外,线程在调用对象的wait方法之前,必须先获取该对象的锁,否则就会抛出一个IllegalMonitorStateException 异常。用代码来说明会比较好理解一点

    public class WaitDemo1 {
        public static void main(String[] args) throws InterruptedException {
            Object o = new Object();
    
            //这里的调用将会抛出一个IllegalMonitorStateException一场
            o.wait();
            //这样的调用才是正确的,在调用之前要先获取o对象锁
            //这里是主线程获取到了锁
            //因此主线程也会被一直阻塞住,因为没有别的线程去唤醒他
            synchronized (o){
                o.wait();
            }
            //或者调用o方法中的一个synchronized方法,也可以获取锁对象
        }
    }
    

    另外,wait方法还可以设置超时参数,wait(long timeout)来实现,到了固定的时间后自动唤醒的效果

    notify/notifyAll方法方法

    当一个调用了锁对象上的notify方法之后,会唤醒一个在该共享变量上调用了wait方法的线程,一个锁对象可能会有多个线程在等待,如果是这种情况的话,notify方法将会随机唤醒一个线程。

    另外,被唤醒的线程不代表他被唤醒之后就可以马上继续执行了,唤醒只是将线程唤醒到了就绪状态,他还是要和其他的线程去竞争锁资源,抢cpu执行权才能继续运行。和wait方法一样,要调用notify方法之前也要先获取该对象的锁,则就会抛IllegalMonitorStateException 异常

    notifyAll这个方法就相对好理解了,唤醒该共享对象上所有因为调用了wait而阻塞的方法。

    看一段代码示例:

    public class WaitDemo2 {
        
        public static void main(String[] args) {
            final Object resource =    new Object();
    
        Thread threadA =   new Thread(() ->{
            synchronized (resource){
                System.out.println("线程A获取了锁");
                try {
                    System.out.println("线程A开始wait");
                    resource.wait();
                    System.out.println("线程A结束wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
            });
        Thread threadB =     new Thread(() ->{
            synchronized (resource){
                System.out.println("线程B获取了锁");
                try {
                    System.out.println("线程B开始wait");
                    resource.wait();
                    System.out.println("线程B结束wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
            });
        Thread threadC =     new Thread(() ->{
    
            synchronized (resource){
                resource.notify();
            }
            });
    
        threadA.start();
        threadB.start();
            //休眠一秒
        Thread.sleep(1000);
        threadC.start();
    
            try {
                threadA.join();
                threadB.join();
                threadC.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main 函数结束");
        }
    }
    
    

    这段代码中创建了三个线程,其中线程A和B调用了wait方法,那么这两个都会被阻塞,然后线程C调用了notify方法,于是会随机唤醒AB其中一个线程,但是另一个线程还是处于阻塞状态。因此,输出结果是这样的

    线程A获取了锁
    线程A开始wait
    线程B获取了锁
    线程B开始wait
    线程A结束wait
    

    由于还有一个线程在阻塞着,又调用了join方法,因此,main函数永远不会停止,但是如果把notify方法改为notifyAll,那么输出结果就是这样的

    线程A获取了锁
    线程A开始wait
    线程B获取了锁
    线程B开始wait
    线程B结束wait
    线程A结束wait
    main 函数结束
    

  • 相关阅读:
    robotframework eclipse Robot Reference libraries不显示(selenium library无法导入)问题解决办法
    Navicat_Keygen_Patch 5.6如何使用
    电子标签拣货系统DPS
    matplotlib中的bar图
    Windows 10 清除文件
    npm包的上传npm包的步骤,与更新和下载步骤
    深入理解JWT的使用场景和优劣
    关于Vue.js去掉#号路由
    关于sklearn中的导包交叉验证问题
    python函数作用域
  • 原文地址:https://www.cnblogs.com/blackmlik/p/12966167.html
Copyright © 2020-2023  润新知