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

相关文章

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

springboot security之前后端分离配置方式

《springbootsecurity之前后端分离配置方式》:本文主要介绍springbootsecurity之前后端分离配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的... 目录前言自定义配置认证失败自定义处理登录相关接口匿名访问前置文章总结前言spring boot secu

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

springboot简单集成Security配置的教程

《springboot简单集成Security配置的教程》:本文主要介绍springboot简单集成Security配置的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录集成Security安全框架引入依赖编写配置类WebSecurityConfig(自定义资源权限规则

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI