Java基础 浅谈线程补充 -------lock实现消费者和生产者以及精确唤醒

本文主要是介绍Java基础 浅谈线程补充 -------lock实现消费者和生产者以及精确唤醒,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们一直使用synchronized来聊经典模式消费者与生产者,在同步安全的时候我们除了讲解synchronized以外,还讲解了lock,对数据进行安全进行保护。那么问题就来了,是否可以通过lock实现消费者和生产者呢?

答案肯定是能,但是应该好奇是如何实现?

先看代码


class Data{private int num=0;Lock lock= new ReentrantLock();public void increment(){lock.lock();try {while (num!=0) {lock.wait();} }catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();} num++;System.out.println(Thread.currentThread().getName()+"现在是number="+num);lock.notifyAll();}public void decrement(){lock.lock();try {while (num==0) {lock.wait();} }catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();} num--;System.out.println(Thread.currentThread().getName()+"现在是number="+num);lock.notinofyAll();}} public class Test {public static void main(String[] args) {Data  data=new Data();new Thread(()->{for (int i=0;i<10;i++){data.decrement();}},"线程A").start();new Thread(()->{for(int i=0;i<10;i++) {data.increment();}} , "线程b").start() ;}
}
//输出
Exception in thread "线程A" Exception in thread "线程b" 线程b现在是number=1java.lang.IllegalMonitorStateExceptionat java.lang.Object.wait(Native Method)at java.lang.Object.wait(Unknown Source)at test.Data.decrement(Test.java:66)at test.Test.lambda$0(Test.java:22)at java.lang.Thread.run(Unknown Source)
java.lang.IllegalMonitorStateExceptionat java.lang.Object.notifyAll(Native Method)at test.Data.increment(Test.java:58)at test.Test.lambda$1(Test.java:31)at java.lang.Thread.run(Unknown Source)

只是简单的讲synchronized换程了lock和unlock,代码编辑器提示可以使用wait方法呢notinofyAll方法,所以第一反应,这个简单,可以直接依葫芦画瓢,然而输出的确实打脸了。

这个异常时一个非法异常,说明在编译没有异常,而是一个运行异常。还有就是为什么可以编译使用lock调用wait?

这个需要看jdk帮助文档:

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

可以看出这继承了object,所以可以使用object中的方法。

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

我们在看 ReentrantLock详细放的时候发现了这个,所以我们可以再看condition是如何实现等待和唤醒功能的。

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

完美不但对功能进行了一个简单解析,而且还给予了一个例子模板,可以从中找出三个方法await(),signal().signalAll()。

其中await等待,可以设置时间,signal唤醒一个等待的线程,signalAll唤醒所有等待的线程。

现在我们就可以通过lock实现消费者和生产者

public class Test {public static void main(String[] args) {Data  data=new Data();new Thread(()->{for (int i=0;i<10;i++){data.decrement();}},"线程A").start();new Thread(()->{for(int i=0;i<10;i++) {data.increment();}} , "线程b").start() ;}
}class Data{private int num=0;Lock lock= new ReentrantLock();Condition notFull  = lock.newCondition(); Condition notEmpty = lock.newCondition(); public void increment(){lock.lock();try {while (num!=0) {notEmpty.await();} num++;System.out.println(Thread.currentThread().getName()+"现在是number="+num);notFull.signalAll();}catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();} }public void decrement(){lock.lock();try {while (num==0) {notFull.await();} num--;System.out.println(Thread.currentThread().getName()+"现在是number="+num);notEmpty.signalAll();}catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();} }
} 
//输出
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0
线程b现在是number=1
线程A现在是number=0

可见输出可以完成用synchronized实现的消费者和生产者的例子。但是通过上面我们可以察觉一件事,那就是conditon,可以实现精确唤醒,比如increment中的condition等待的是notEmpty,而唤醒的时候使用的是notFull。

所以可以实现精确唤醒,具体看代码。

public class Test {public static void main(String[] args) {Step  step=new Step();new Thread(()->{for (int i = 0; i <10; i++) {step.step_first();}},"线程A").start();new Thread(()->{for (int i = 0; i <10; i++) {step.step_second();}},"线程b").start();new Thread(()->{for (int i = 0; i <10; i++) {step.step_thrid();}},"线程c").start();}}class Step{int num=1;Lock lock= new ReentrantLock();Condition step1  = lock.newCondition();Condition step2  = lock.newCondition();Condition step3  = lock.newCondition();public void step_first() {lock.lock();try {while(num!=1) {step1.await();}System.out.println(Thread.currentThread().getName());num=2;step2.signalAll();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();}}public void step_second() {lock.lock();try {while(num!=2) {step2.await();}System.out.println(Thread.currentThread().getName());num=3;step3.signalAll();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();}}public void step_thrid() {lock.lock();try {while(num!=3) {step3.await();}System.out.println(Thread.currentThread().getName());num=1;step1.signalAll();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {lock.unlock();}}
}
//输出
线程A
线程b
线程c
线程A
线程b
线程c
线程A
线程b
线程c
线程A
线程b
线程c
线程A
线程b
线程c
线程A
线程b
线程c
//后面一样

可以看出同各国condition可以实现精准唤醒。a,b,c相互交替,这个可以实现比如购物支付这样的功能。

这篇关于Java基础 浅谈线程补充 -------lock实现消费者和生产者以及精确唤醒的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1073129

相关文章

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

Python使用pip工具实现包自动更新的多种方法

《Python使用pip工具实现包自动更新的多种方法》本文深入探讨了使用Python的pip工具实现包自动更新的各种方法和技术,我们将从基础概念开始,逐步介绍手动更新方法、自动化脚本编写、结合CI/C... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

在Linux中改变echo输出颜色的实现方法

《在Linux中改变echo输出颜色的实现方法》在Linux系统的命令行环境下,为了使输出信息更加清晰、突出,便于用户快速识别和区分不同类型的信息,常常需要改变echo命令的输出颜色,所以本文给大家介... 目python录在linux中改变echo输出颜色的方法技术背景实现步骤使用ANSI转义码使用tpu

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

java中反射Reflection的4个作用详解

《java中反射Reflection的4个作用详解》反射Reflection是Java等编程语言中的一个重要特性,它允许程序在运行时进行自我检查和对内部成员(如字段、方法、类等)的操作,本文将详细介绍... 目录作用1、在运行时判断任意一个对象所属的类作用2、在运行时构造任意一个类的对象作用3、在运行时判断