Java线程等待唤醒的三种方法

news2024/9/17 8:26:35

线程等待唤醒的三种方法

需求:我们实现A线程等待B线程执行完在执行。

Object下面的wait()和notify()

使用Object中的wait()方法让线程等待,使用Object中的notify()方法唤醒线程

public static void main(String[] args) throws InterruptedException {
    Object o = new Object();
    new Thread(() -> {
        synchronized (o) {
            log.info("准备执行A");
            try {
                o.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("A执行完成");
        }
    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        synchronized (o) {
            log.info("我是B,我要唤醒A");
            o.notify();
        }
    }, "B").start();
}

运行:

15:36:43.390 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
15:36:44.395 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
15:36:44.395 [A] INFO com.yougong.digitalwallet.controller.TestTest - A执行完成
    

思考1

  • 如果去掉 synchronized,再次执行
public static void main(String[] args) throws InterruptedException {
    Object o = new Object();
    new Thread(() -> {
        //synchronized (o) {
        log.info("准备执行A");
        try {
            o.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("A执行完成");
        //}
    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        //synchronized (o) {
        log.info("我是B,我要唤醒A");
        o.notify();
        //}
    }, "B").start();
}

结果:

15:38:58.016 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
Exception in thread "A" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at com.yougong.digitalwallet.controller.TestTest.lambda$main$0(TestTest.java:22)
	at java.lang.Thread.run(Thread.java:748)
15:38:59.029 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
Exception in thread "B" java.lang.IllegalMonitorStateException
	at java.lang.Object.notify(Native Method)
	at com.yougong.digitalwallet.controller.TestTest.lambda$main$1(TestTest.java:35)
	at java.lang.Thread.run(Thread.java:748)

思考2

先 notify 再 wait 会怎么

public static void main(String[] args) throws InterruptedException {
    Object o = new Object();
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        synchronized (o) {
            log.info("准备执行A");
            try {
                o.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("A执行完成");
        }
    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        synchronized (o) {
            log.info("我是B,我要唤醒A");
            o.notify();
        }
    }, "B").start();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBMmUrmE-1688112916989)(C:\Users\86183\AppData\Roaming\Typora\typora-user-images\image-20230630154157434.png)]

发现:程序无法执行,无法唤醒

总结

  • wait和notify方法必须要在同步块或者方法里面,且成对出现使用

  • 先wait后notify才OK

Condition类的await()和single()方法

使用JUC包中Condition的await()方法让线程等待,使用signal()方法唤醒线程

public static void main(String[] args) throws InterruptedException {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    new Thread(() -> {
        log.info("准备执行A");
        lock.lock();
        try {
            condition.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        log.info("A执行完成");

    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        lock.lock();
        try {
            log.info("我是B,我要唤醒A");
            condition.signal();
        } finally {
            lock.unlock();
        }
    }, "B").start();
}

运行:

15:45:28.053 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
15:45:29.056 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
15:45:29.056 [A] INFO com.yougong.digitalwallet.controller.TestTest - A执行完成

思考1

如果去掉 lock,再次执行

public static void main(String[] args) throws InterruptedException {
    //m1();
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    new Thread(() -> {
        log.info("准备执行A");
        //lock.lock();
        try {
            condition.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            //lock.unlock();
        }
        log.info("A执行完成");

    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        //lock.lock();
        try {
            log.info("我是B,我要唤醒A");
            condition.signal();
        } finally {
            //lock.unlock();
        }
    }, "B").start();
}

运行:

15:48:05.392 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
Exception in thread "A" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
	at com.yougong.digitalwallet.controller.TestTest.lambda$main$0(TestTest.java:28)
	at java.lang.Thread.run(Thread.java:748)
15:48:06.404 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
Exception in thread "B" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1939)
	at com.yougong.digitalwallet.controller.TestTest.lambda$main$1(TestTest.java:44)
	at java.lang.Thread.run(Thread.java:748)

思考2

先 signal 再 await 会怎么

代码:

public static void main(String[] args) throws InterruptedException {
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("准备执行A");
        lock.lock();
        try {
            condition.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        log.info("A执行完成");

    }, "A").start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        lock.lock();
        try {
            log.info("我是B,我要唤醒A");
            condition.signal();
        } finally {
            lock.unlock();
        }
    }, "B").start();
}

运行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nS6JELET-1688112916990)(C:\Users\86183\AppData\Roaming\Typora\typora-user-images\image-20230630154901490.png)]

总结

  • await和single方法必须要在同步块或者方法里面,且成对出现使用

  • 先await后single才OK

LockSupport类的park()和unpark()方法

LockSupport类可以阻塞当前线程以及唤醒指定被阻塞的线程

LockSupport类使用的是一种名为 Permit(许可)的概念做到阻塞和唤醒线程的,每一个线程都有一个许可(Permit),permit只存在两个值0或者1,默认为0.

调用LockSupport.park()时,当前线程就会阻塞,因为permit默认为0,直到别的线程将当前线程的permit设置成1时,park方法才会被唤醒,然后会将permit设置为0,继续执行park后面的代码。

调用LockSupport的unpark(thread)方法时,会将thread线程的permit就会被设置成1,然后自动唤醒thread线程继续执行之前阻塞的park方法后面的代码。注意:unpark(thread)无论执行多少遍,permit的值只可能是1,不会依次累加。

代码:

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        log.info("准备执行A");
        LockSupport.park();
        log.info("A执行完成");
    }, "A");
    thread.start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        log.info("我是B,我要唤醒A");
        LockSupport.unpark(thread);
    }, "B").start();
}

运行:

16:12:03.318 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
16:12:04.320 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
16:12:04.320 [A] INFO com.yougong.digitalwallet.controller.TestTest - A执行完成

思考2

先 unpark 再 park会怎么

代码:

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        log.info("准备执行A");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        LockSupport.park();
        log.info("A执行完成");
    }, "A");
    thread.start();

    TimeUnit.SECONDS.sleep(1);

    new Thread(() -> {
        log.info("我是B,我要唤醒A");
        LockSupport.unpark(thread);
    }, "B").start();
}

运行:

16:12:57.447 [A] INFO com.yougong.digitalwallet.controller.TestTest - 准备执行A
16:12:58.453 [B] INFO com.yougong.digitalwallet.controller.TestTest - 我是B,我要唤醒A
16:13:00.450 [A] INFO com.yougong.digitalwallet.controller.TestTest - A执行完成

没问题。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705262.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提高企业云服务性价比,亚马逊云科技为用户提供全面和深入的算力支持

6月27日至28日,2023亚马逊云科技中国峰会于上海顺利召开。在本次峰会上,似乎找寻到了云计算领域竞争对手均日渐成熟,而亚马逊云科技却能一直保持领先地位的原因——过去的十几年里,亚马逊云科技“基于客户需求,快速进行…

django-vue-admin ubuntu 20.04 环境准备 记录

django-vue-admin 运行记录 https://django-vue-admin.com/document/hjbs.html https://django-vue-admin.com/document/hjbs.html https://bbs.django-vue-admin.com/article/9.html https://gitee.com/liqianglog/django-vue-admin/tree/demo_project 1. 安装 ubuntu-20.04…

【八股】【C++】函数与类

这里写目录标题 形参与实参的区别函数调用过程指针和引用当函数参数引用作为函数参数有哪些好处回调函数友元函数重载匹配运算符重载直接初始化与拷贝初始化函数指针C中struct(结构)和class(类)的区别C有哪几种构造函数构造函数的…

中华太极图

python代码: import turtle turtle.circle(100) turtle.color(black,black) turtle.begin_fill() turtle.circle(50,180) turtle.circle(-50,180) turtle.right(180) turtle.circle(100,180) turtle.end_fill() turtle.penup() turtle.goto(0,25) turtle.pendown()…

06_pinctr子系统与gpio子系统

目录 pinctrl子系统简介 I.MX6ULL的pinctrl子系统驱动 PIN驱动程序讲解 设备树中添加pinctrl节点模板 gpio子系统简介 I.MX6ULL的gpio子系统驱动 GPIO驱动程序简介 gpio子系统API函数 设备树中添加gpio节点模板 与gpio相关的OF函数 LED实验 LED灯驱动程序编写 运行…

单片机中断

89C51/52的中断系统有5个中断源 ,2个优先级,可实现二级中断嵌套 。 ( P3.2)可由IT0(TCON.0)选择其为低电平有效还是下降沿有效。当CPU检测到P3.2引脚上出现有效的中断信号时,中断标志IE0(TCON.1)置1,向CPU申请中断。 &…

基于 unity 配置 adb

1.打开环境变量配置path的环境 2 找到自己的unity安装目录,找到对应路径 配置到 path 属性中 C:\~\Editor\2021.3.0f1c1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools 3 应用保存即可

chatgpt赋能python:Win7下Python:轻松实现SEO优化

Win7下Python:轻松实现SEO优化 Python作为一门高级程序语言,不仅广泛应用于人工智能和数据科学领域,也在Web开发中扮演着重要角色。在SEO方面,Python也展现了强大的能力。本文将介绍如何在Win7下使用Python实现SEO优化。 什么是…

chatgpt赋能python:同一行Python给两个变量赋值:如何提高编程效率?

同一行Python给两个变量赋值:如何提高编程效率? 作为Python编程方面经验丰富的工程师,我们都知道Python是一种非常易学易用的编程语言,其灵活性和高效性问题业已广为人知。然而,当我们在同时对多个变量进行赋值时&…

docker学习(一)docker概述

Docker 是什么 Docker 是一个开源的应用容器引擎,基于 Go 语言,并遵从 Apache2.0 协议开源。它可以让开发者打包应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker 可用于…

MobaXterm通过RDP连接Ubuntu

文章目录 RDP,FTP和SSH基础知识通过RDP连接UbuntuUbuntu安装RDP开放RDP默认端口使用MobaXterm进行连接 RDP,FTP和SSH基础知识 RDP, FTP和SSH是计算机网络中常用的远程连接协议,用于在不同计算机之间进行远程访问和文件传输。 RDP (Remote De…

Python L2: String、Class、Json

定义一个Python class class Node:def __init__(self):self.ip ""self.pods []self.count 0 Json 对象(instance) 转 dict 和字符串 n Node() n.count 1 n.ip "127.0.0.1" n.pods ["pod-x", "pod-y", "pod…

uniapp 一键登录

官网文档地址https://uniapp.dcloud.net.cn/univerify.html 一、开发前准备 1、需要先开通uni一键登录服务 开通成功后会得到 apiKey、apiSecret。这2个信息,后续需要配置在uniCloud的云函数里。同时注意保密,这2个信息也是计费凭证 2、开通uniCloud服…

机器学习实战 | emojify 使用Python创建自己的表情符号(深度学习初级)

目录 简介技术流程1. 加载依赖包2. 初始化训练和验证生成器3. 建立网络结构4. 编译和训练模型5. 保存模型权重6. 输出预测结果 完整程序1. train.py程序2. gui.py程序 简介 准备写个系列博客介绍机器学习实战中的部分公开项目。首先从初级项目开始。 本文主要介绍机器学习项目…

.Net 4726.0 Razor编译时的小差异

前言 几个月前在进行着.Net 472到6.0的升级,复用原有代码,在对Razor进行迁移中,发现原运行正常的代码,却存在报错,深入研究发现是Core下对Razor编译有一些变动。 问题复现 472 创建视图 新建.Net Framework下Mvc&#…

常州工学院单片机及应用系统设计2021-2022 学年第 二 学期 考试类型 开卷 课程编码 0302005

第一题 #include "SC95F861x_C.H" #include <INTRINS.H> unsigned char keydata0; void delay(unsigned int timer) //延时函数 { while(timer>0) timer--; } void IOinit() { P5CON0x00; P5PH0x03; P3CON0xFF; P3PH0xFF; } void readke…

字节跳动算法 提前批offer复盘

作者 | zjwang 面试锦囊之面经分享系列&#xff0c;持续更新中 欢迎后台回复"面试"加入讨论组交流噢 写在前面 北航本硕&#xff0c;非科班对搜索推荐比较感兴趣&#xff0c;平时看的文章比较多&#xff0c;所以聊的比较偏这一块大四时一段五个月的nlp方向实习&…

Dlib —— Windows下Vs2017编译dlib源码

Dlib Dlib 是一个现代C工具包&#xff0c;包含机器学习算法和 用于创建复杂软件的工具&#xff0c;C解决现实世界的问题。 它用于工业界和学术界的广泛领域 包括机器人、嵌入式设备、手机和大型高 性能计算环境。Dlib的开源许可允许您在任何应用程序中免费使用它。   Dlib相关…

项目计划、进度与控制

思维导图 项目计划、进度与控制-思维导图 第一部分 项目管理概述 什么是项目 约瑟夫朱兰博士也说过&#xff0c;项目就是在已经确定好的时间内必须解决的问题 什么是项目管理 图1-1 项目管理就是工具、人和系统 image.png 组织是人的集合&#xff0c;过程是人在处理。如果人…

Docker cuda libnvidia-compute Invalid cross-device link

docker apt 安装 cuda rootyeqiang-PC:/opt/speccpu2006# docker exec -it 881 /bin/bash root8815d0425401:/# apt --fix-broken install Reading package lists... Done Building dependency tree Reading state information... Done Correcting dependencies... Don…