多线程五-线程通信之wait与notify

news/2024/9/21 9:53:21

wait与notify用于syncronized的线程间通信的一种,wait用来阻塞线程并释放锁,notify用来唤醒线程。他们与condition作用基本一致,但是由于syncronized为jdk实现,阅读源码有难度,所以通过了解其原理,用来帮助我们后续理解condition的源码。
可以通过下面一张图来理解:
syncronized.png
下面通过一个简单的生产者与消费者的例子来体会一下这两个API的用法
生产者代码:

package com.caozz.demo5.concurrent;import java.util.Queue;public class Producer implements Runnable{private Queue<String> bags;private int maxSize;public Producer(Queue<String> bags, int maxSize) {this.bags = bags;this.maxSize = maxSize;}@Overridepublic void run(){int i = 0;while (true) {i++;synchronized (bags) {if (bags.size() >= maxSize) {System.out.println("bags 满了");try {bags.wait();//满了则阻塞当前线程并释放} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("生产者生产: bag" + i);bags.add("bag" + i);bags.notify();//表示已经生产数据了,消费者可以消费了(消费者不一定能抢到锁)}}}}

消费者代码:

package com.caozz.demo5.concurrent;import java.util.Queue;public class Consumer  implements Runnable{private Queue<String> bags;public Consumer(Queue<String> bags){this.bags = bags;}@Overridepublic void run() {while (true) {//与生产者肯定是同一个对象,否则不是同一把锁就无法实现线程间通信了synchronized (bags) {if (bags.isEmpty()) {System.out.println("bags 为空");try {bags.wait();} catch (InterruptedException e) {e.printStackTrace();}}String bag = bags.remove();System.out.println("消费者消费:" + bag);//如果生产者满了被阻塞,此时消费了所以必然可以继续生产//这里只是唤醒线程,但是生产者并不能马上执行,因为需要等到同步代码块执行完成,即monitorexit指令执行完成bags.notify();}}}
}

测试:

package com.caozz.demo5.controller;import com.caozz.demo5.concurrent.Consumer;
import com.caozz.demo5.concurrent.Producer;import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Test {public static void main(String[] args) throws InterruptedException {
//        Lock lock = new ReentrantLock(true);
//        lock.lock();
//        lock.unlock();Queue<String> bags = new LinkedList<>();int maxSize = 500;Producer producer = new Producer(bags, maxSize);Consumer consumer = new Consumer(bags);new Thread(producer).start();Thread.sleep(1);new Thread(consumer).start();}
}

部分执行结果:省略号省略得内容连续

消费者消费:bag183545
消费者消费:bag183546
消费者消费:bag183547
生产者生产: bag183572
生产者生产: bag183573
...
生产者生产: bag183580
消费者消费:bag183548
...
消费者消费:bag183580
bags 为空
生产者生产: bag183581
生产者生产: bag183582
消费者消费:bag183581
消费者消费:bag183582
bags 为空
生产者生产: bag183583
...
生产者生产: bag183591
消费者消费:bag183583
消费者消费:bag183584
欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

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

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

相关文章

帝国cms忘记了后台密码怎么办

如果你忘记了帝国CMS(EmpireCMS)的后台管理员密码,可以通过以下步骤来重置密码: 方法 1: 通过数据库重置密码登录数据库:使用数据库管理工具(如phpMyAdmin)连接到你的数据库。 登录数据库管理界面。找到用户表:通常表名为 phome_enewsuser(具体表名可能有所不同)。 打…

如何恢复对帝国CMS的访问,忘记账号密码的解决方案

如果你忘记了帝国CMS的后台管理员账号和密码,可以通过以下步骤来恢复对系统的访问: 方法 1: 通过数据库重置密码登录数据库:使用数据库管理工具(如phpMyAdmin)连接到你的数据库。 登录数据库管理界面。找到用户表:通常表名为 phome_enewsuser(具体表名可能有所不同)。 …

编程日记 后端tags过滤器

编程日记 后端tags过滤器这样查出来了所有的信息,不对 检查是这个地方有问题改掉 @Overridepublic List<User> searchUsersByTags(List<String> tagNameList) {//1.先查询所有用户QueryWrapper<User> queryWrapper = new QueryWrapper<>();List<Us…

PbootCms忘记后台管理员密码这样找回

如果你忘记了PbootCMS后台管理员的密码,可以通过以下步骤来重置密码: 方法 1: 使用官方提供的密码重置工具下载密码重置工具:下载官方提供的密码重置工具 resetpw.php。 将 resetpw.php 文件上传到网站根目录。访问重置工具:在浏览器中访问 http://[您的域名]/resetpw.php。…

织梦CMS 忘记后台管理员密码的一种解决方法

如果你忘记了织梦CMS(Dedecms)的后台管理员密码,并且拥有对MySQL数据库的操作权限,可以按照以下步骤重置密码: 步骤 1: 登录 MySQL 数据库打开 MySQL 客户端,如 phpMyAdmin 或命令行工具。 登录 MySQL 数据库:sqlmysql -u 用户名 -p输入密码后登录。步骤 2: 选择对应的数…

编程日记 后端使用redis

编程日记 后端使用redis 问题:在写伙伴匹配系统的时候,要使用redis存储数据,需要在xml文件中设置spring.session.tore-type=redis 但是3.x版本的spring不再有这个参数。 那么怎么设置是否使用redis存储呢?只要导入了org.springframework.session包那就启用,不导入就不启用…

如何重置帝国CMS的忘记密码

重置帝国CMS的后台管理员密码可以通过以下方法实现: 方法一:使用官方提供的密码重置工具 如果帝国CMS官方提供了密码重置工具,可以使用该工具来重置密码:下载重置工具:从帝国CMS官方网站或其他可信来源下载官方提供的密码重置工具。 上传文件:将下载的重置工具文件上传到…

帝国cms忘记密码怎么办

如果你忘记了帝国CMS的管理员密码,可以通过以下步骤来重置密码: 1. 登录数据库 首先,你需要登录到你的数据库。这通常可以通过以下几种方式完成:phpMyAdmin:通过Web界面登录数据库。 命令行工具:使用MySQL命令行工具登录数据库。 主机控制面板:通过主机控制面板(如cPan…