热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JUC:4_1并发协作模型:生产者消费者模型

JUC:4_1并发协作模型:生产者消费者模型线程通信问题synchronized版本的管程法Lock版本的管程法线程通信问题线程之间的通信问题

JUC:4_1并发协作模型:生产者消费者模型

  • 线程通信问题
  • synchronized版本的管程法
  • Lock版本的管程法


线程通信问题

线程之间的通信问题,就是生产者和消费者问题,也就是如何做到多个线程交替执行。

并发协作模型:生产者消费者模型 解决方式1.管程法
并发协作模型:生产者消费者模型 解决方式2.信号灯法

上面两个是基于synchronized、wait、notify来去做的,现在改为Lock去做。

synchronized版本的管程法

/*** 并发协作模型"生产者/消费者模式"* 线程之间的通信问题,就是生产者和消费者问题,也就是如何做到多个线程交替执行* 比如一个线程++A* 一个线程--A* 需要先放入再执行另一个操作*/
public class TestPC {public static void main(String[] args) {SyncContainer container &#61; new SyncContainer();//生产者new Thread(() -> {for (int i &#61; 0; i < 100; i&#43;&#43;) {container.push(new Product(i));System.out.println("将产品放入缓冲区&#xff1a;" &#43; i);}}).start();//消费者new Thread(() -> {for (int i &#61; 0; i < 100; i&#43;&#43;) {System.out.println("消费产品" &#43; container.pop().getPid());}}).start();}
}//产品
class Product {private int pid;//产品编号public int getPid() {return pid;}public void setPid(int pid) {this.pid &#61; pid;}public Product(int pid) {this.pid &#61; pid;}
}//缓冲区
class SyncContainer {//容器大小&#xff0c;默认容量指定10private static final int DEFAULT_CAPACITY &#61; 10;Product[] products &#61; new Product[DEFAULT_CAPACITY];//容器计数器int count &#61; 0;//生产者放产品public synchronized void push(Product product) {if (count &#61;&#61; products.length) {//容器已满&#xff0c;需要等待消费//通知消费者消费&#xff0c;生产者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//容器不满&#xff0c;可以放产品products[count] &#61; product;count&#43;&#43;;//通知消费者消费&#xff0c;这里用notifyAll和notify结果都是一样的&#xff0c;因为不会同时阻塞this.notifyAll();}//消费者消费产品public synchronized Product pop() {//判断容器有无产品&#xff0c;无则阻塞if (count &#61;&#61; 0) {//等待生产者生产&#xff0c;消费者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//可以消费&#xff0c;这里主要&#xff1a;count--必须在前&#xff0c;因为生产者生产之后count&#43;&#43;会&#43;1count--;Product product &#61; products[count];//通知生产者生产&#xff0c;这里用notifyAll和notify结果都是一样的&#xff0c;因为不会同时阻塞this.notify();return product;}
}

输出&#xff1a;

将产品放入缓冲区&#xff1a;0
将产品放入缓冲区&#xff1a;1
将产品放入缓冲区&#xff1a;2
将产品放入缓冲区&#xff1a;3
将产品放入缓冲区&#xff1a;4
将产品放入缓冲区&#xff1a;5
将产品放入缓冲区&#xff1a;6
将产品放入缓冲区&#xff1a;7
将产品放入缓冲区&#xff1a;8
将产品放入缓冲区&#xff1a;9
消费产品9
将产品放入缓冲区&#xff1a;10
消费产品10
将产品放入缓冲区&#xff1a;11
将产品放入缓冲区&#xff1a;12
消费产品11
消费产品12
将产品放入缓冲区&#xff1a;13
消费产品13
将产品放入缓冲区&#xff1a;14
消费产品14
将产品放入缓冲区&#xff1a;15
消费产品15
将产品放入缓冲区&#xff1a;16
将产品放入缓冲区&#xff1a;17
消费产品16
消费产品17
将产品放入缓冲区&#xff1a;18
将产品放入缓冲区&#xff1a;19
消费产品18
消费产品19
将产品放入缓冲区&#xff1a;20
将产品放入缓冲区&#xff1a;21
消费产品20
消费产品21
将产品放入缓冲区&#xff1a;22
消费产品22
将产品放入缓冲区&#xff1a;23
消费产品23
消费产品24
将产品放入缓冲区&#xff1a;24
消费产品8
将产品放入缓冲区&#xff1a;25
消费产品25
将产品放入缓冲区&#xff1a;26
消费产品26
将产品放入缓冲区&#xff1a;27
将产品放入缓冲区&#xff1a;28
消费产品27
将产品放入缓冲区&#xff1a;29
消费产品29
将产品放入缓冲区&#xff1a;30
消费产品30
将产品放入缓冲区&#xff1a;31
消费产品31
将产品放入缓冲区&#xff1a;32
消费产品32
将产品放入缓冲区&#xff1a;33
消费产品33
将产品放入缓冲区&#xff1a;34
消费产品34
将产品放入缓冲区&#xff1a;35
消费产品35
将产品放入缓冲区&#xff1a;36
消费产品36
将产品放入缓冲区&#xff1a;37
消费产品37
将产品放入缓冲区&#xff1a;38
消费产品38
将产品放入缓冲区&#xff1a;39
消费产品39
将产品放入缓冲区&#xff1a;40
消费产品40
将产品放入缓冲区&#xff1a;41
消费产品41
将产品放入缓冲区&#xff1a;42
消费产品42
将产品放入缓冲区&#xff1a;43
消费产品43
将产品放入缓冲区&#xff1a;44
消费产品44
将产品放入缓冲区&#xff1a;45
消费产品45
将产品放入缓冲区&#xff1a;46
消费产品46
将产品放入缓冲区&#xff1a;47
消费产品47
将产品放入缓冲区&#xff1a;48
消费产品48
将产品放入缓冲区&#xff1a;49
消费产品49
将产品放入缓冲区&#xff1a;50
消费产品50
将产品放入缓冲区&#xff1a;51
消费产品51
将产品放入缓冲区&#xff1a;52
消费产品52
将产品放入缓冲区&#xff1a;53
消费产品53
将产品放入缓冲区&#xff1a;54
消费产品54
将产品放入缓冲区&#xff1a;55
消费产品55
将产品放入缓冲区&#xff1a;56
消费产品56
将产品放入缓冲区&#xff1a;57
消费产品57
将产品放入缓冲区&#xff1a;58
消费产品58
将产品放入缓冲区&#xff1a;59
消费产品59
将产品放入缓冲区&#xff1a;60
消费产品60
将产品放入缓冲区&#xff1a;61
消费产品61
将产品放入缓冲区&#xff1a;62
消费产品62
将产品放入缓冲区&#xff1a;63
将产品放入缓冲区&#xff1a;64
消费产品63
消费产品64
消费产品65
将产品放入缓冲区&#xff1a;65
消费产品28
将产品放入缓冲区&#xff1a;66
消费产品66
将产品放入缓冲区&#xff1a;67
消费产品67
将产品放入缓冲区&#xff1a;68
消费产品68
将产品放入缓冲区&#xff1a;69
消费产品69
将产品放入缓冲区&#xff1a;70
消费产品70
将产品放入缓冲区&#xff1a;71
消费产品71
将产品放入缓冲区&#xff1a;72
消费产品72
将产品放入缓冲区&#xff1a;73
消费产品73
将产品放入缓冲区&#xff1a;74
消费产品74
将产品放入缓冲区&#xff1a;75
将产品放入缓冲区&#xff1a;76
消费产品75
将产品放入缓冲区&#xff1a;77
消费产品77
将产品放入缓冲区&#xff1a;78
将产品放入缓冲区&#xff1a;79
消费产品78
消费产品79
将产品放入缓冲区&#xff1a;80
将产品放入缓冲区&#xff1a;81
消费产品80
消费产品81
将产品放入缓冲区&#xff1a;82
消费产品82
将产品放入缓冲区&#xff1a;83
消费产品83
将产品放入缓冲区&#xff1a;84
消费产品84
将产品放入缓冲区&#xff1a;85
将产品放入缓冲区&#xff1a;86
消费产品85
消费产品86
将产品放入缓冲区&#xff1a;87
消费产品87
将产品放入缓冲区&#xff1a;88
消费产品88
将产品放入缓冲区&#xff1a;89
消费产品89
消费产品90
将产品放入缓冲区&#xff1a;90
消费产品76
将产品放入缓冲区&#xff1a;91
消费产品91
将产品放入缓冲区&#xff1a;92
消费产品92
将产品放入缓冲区&#xff1a;93
消费产品93
将产品放入缓冲区&#xff1a;94
消费产品94
将产品放入缓冲区&#xff1a;95
消费产品95
将产品放入缓冲区&#xff1a;96
消费产品96
将产品放入缓冲区&#xff1a;97
消费产品97
将产品放入缓冲区&#xff1a;98
消费产品98
将产品放入缓冲区&#xff1a;99
消费产品99
消费产品7
消费产品6
消费产品5
消费产品4
消费产品3
消费产品2
消费产品1
消费产品0

Lock版本的管程法

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 并发协作模型"生产者/消费者模式"* 线程之间的通信问题&#xff0c;就是生产者和消费者问题&#xff0c;也就是如何做到多个线程交替执行* 比如一个线程&#43;&#43;A* 一个线程--A* 需要先放入再执行另一个操作*/
public class TestPC2 {public static void main(String[] args) {SyncContainer container &#61; new SyncContainer();//生产者new Thread(() -> {for (int i &#61; 0; i < 100; i&#43;&#43;) {container.push(new Product(i));System.out.println("将产品放入缓冲区&#xff1a;" &#43; i);}}).start();//消费者new Thread(() -> {for (int i &#61; 0; i < 100; i&#43;&#43;) {System.out.println("消费产品:" &#43; container.pop().getPid());}}).start();}
}//产品
class Product2 {private int pid;//产品编号public int getPid() {return pid;}public void setPid(int pid) {this.pid &#61; pid;}public Product2(int pid) {this.pid &#61; pid;}
}//缓冲区
class SyncContainer2 {//容器大小&#xff0c;默认容量指定10private static final int DEFAULT_CAPACITY &#61; 10;Product2[] products &#61; new Product2[DEFAULT_CAPACITY];final Lock lock &#61; new ReentrantLock();//默认非公平锁&#xff0c;可以添加true类型设置为公平锁final Condition productor &#61; lock.newCondition();final Condition consumer &#61; lock.newCondition();//容器计数器int count &#61; 0;//生产者放产品public void push(Product2 product) {lock.lock();//加锁//lock.tryLock();//尝试获取锁&#xff0c;这个就是和synchronized区别&#xff0c;不会傻傻的一直等待try {if (count > products.length) {////容器已满&#xff0c;需要等待消费//通知消费者消费&#xff0c;生产者等待try {productor.await();} catch (InterruptedException e) {e.printStackTrace();}}//容器不满&#xff0c;可以放产品products[count] &#61; product;count&#43;&#43;;//通知消费者消费&#xff0c;这里与sychonized的唤醒时用的notifyAll和notify不同&#xff0c;用signalconsumer.signal();} finally {lock.unlock();//解锁}}//消费者消费产品public Product2 pop() {lock.lock();//加锁Product2 product;try {//lock.tryLock();//尝试获取锁&#xff0c;这个就是和synchronized区别&#xff0c;不会傻傻的一直等待//判断容器有无产品&#xff0c;无则阻塞if (count &#61;&#61; 0) {//等待生产者生产&#xff0c;消费者等待try {consumer.wait();} catch (InterruptedException e) {e.printStackTrace();}}//可以消费&#xff0c;这里主要&#xff1a;count--必须在前&#xff0c;因为生产者生产之后count&#43;&#43;会&#43;1count--;product &#61; products[count];productor.signal();} finally {lock.unlock();}return product;}
}


推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
author-avatar
大爱走钢索的人_738
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有