引言

使用Condition实现生产者-消费者模型,并与wait和notify实现的效果相对比。

wait/notify模拟生产者-消费者

面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法能够支持2个生产线程以及10个消费者线程的阻塞调用。

在《Effective Java》一书中提到:wait()方法()绝大多数情况下都是和while一起使用的。这是因为,当wait()执行完成后,会立刻释放当前锁,如果这时其他线程立刻获得锁并对变量进行操作,会出现数据不一致的情况,使用while可以确保数据不会出现不一致的情况。

public class ProducerConsumer1<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10;// 最多10个元素private int count = 0;public synchronized void put(T t) {while (lists.size() == this.MAX) {// 想想为什么用while而不是iftry {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}lists.add(t);count++;this.notifyAll();// 通知消费者线程进行消费}public synchronized T get() {T t = null;while (lists.size() == 0) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}t = lists.removeFirst();count--;this.notifyAll();// 通知生产者进行生产return t;}public static void main(String[] args) {ProducerConsumer1<String> c = new ProducerConsumer1<>();// 启动消费者线程for (int i = 0; i < 10; i++) {new Thread(() -> {for (int j = 0; j < 5; j++) {System.out.println(c.get());}}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 0; i < 2; i++) {new Thread(() -> {for (int j = 0; j < 25; j++) {c.put(Thread.currentThread().getName() + " " + j);}}).start();}}
}

Condition模拟生产者-消费者

使用Lock和Condition来实现类似需求时,可以更加精确的指定哪些线程被唤醒,这比notifyAll()效率更高一些。

将上面的程序代码进行改写:

public class ProducerConsumer2<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10;private int count = 0;private Lock lock = new ReentrantLock();private Condition producer = lock.newCondition();private Condition consumer = lock.newCondition();public void put(T t) {try {lock.lock();while (lists.size() == MAX) {producer.await();}lists.add(t);++count;consumer.signalAll(); // 通知消费者线程进行消费} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public T get() {T t = null;try {lock.lock();while (lists.size() == 0) {consumer.await();}t = lists.removeFirst();count--;producer.signalAll();// 通知生产者进行生产} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return t;}public static void main(String[] args) {ProducerConsumer2<String> c = new ProducerConsumer2<>();// 启动消费者线程for (int i = 0; i < 10; i++) {new Thread(() -> {for (int j = 0; j < 5; j++) {System.out.println(c.get());}}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}for (int i = 0; i < 2; i++) {new Thread(() -> {for (int j = 0; j < 25; j++) {c.put(Thread.currentThread().getName()+ " " + j);}}).start();}}
}

鸣谢

《马士兵老师高并发编程系列》

Java 多线程 —— AQS 原理相关推荐

  1. Java多线程 - AQS详解

    介绍 AQS是java.util.concurrent.locks下类AbstractQueuedSynchronizer的简称,是用于 通过Java源码来构建多线程的锁和同步器的一系列框架,用于Ja ...

  2. 面试突然问Java多线程底层原理,我哭了!

    兄弟们,不要踩坑啊,我原本打算在金九银十之前换份工作,结果出去第一面就被干懵了! 面试官上来就问我了解不了解多线程,我感觉我还可以,我就和他说:必须的! 不过,他直接问了多线程的底层原理,这我都是一知 ...

  3. Java 多线程 —— AQS 详解

    引言 AQS 是AbstractQuenedSynchronizer 的缩写,抽象的队列式同步器,它是除了java自带的synchronized关键字之外的锁机制.是 JUC 下的重要组件. 相关产物 ...

  4. 字节跳动学习笔记:java多线程实现原理

    01 Mysql 1. 数据库三范式及判断.E-R图 2. innodb和myisam存储引擎的区别 3. 索引分类(主键.唯一索引.全文索引.覆盖索引等等),最左前缀原则,哪些条件无法使用索引 4. ...

  5. java多线程aqs实现工具类_Java并发多线程 - 并发工具类JUC

    (adsbygoogle = window.adsbygoogle || []).push({}); 安全共享对象策略 1.线程限制 : 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改 ...

  6. java resume过时方法_学点开发|关于Java多线程用法解析

    在进行学习之前,我们先来了解下,什么是Java多线程: 多线程是实现并发机制的一种有效手段.进程和线程一样,都是实现并发的一个基本单位.为了让大家更清晰读懂关于Java多线程用法,由以下几点入手学,帮 ...

  7. 7个连环问揭开java多线程背后的弯弯绕

    摘要:很多java入门新人一想到java多线程, 就会觉得很晕很绕,什么可见不可见的,也不了解为什么sync怎么就锁住了代码. 本文分享自华为云社区<java多线程背后的弯弯绕绕到底是什么? 7 ...

  8. [遇见时光]Java多线程

    原博:http://www.codeceo.com/article/java-mult-thread.html,本博文加入自己的理解.更详细参考http://blog.csdn.net/evankak ...

  9. Java多线程系列(十):源码剖析AQS的实现原理

    在并发编程领域,AQS号称是并发同步组件的基石,很多并发同步组件都是基于AQS实现,所以想掌握好高并发编程,你需要掌握好AQS. 本篇主要通过对AQS的实现原理.数据模型.资源共享方式.获取锁的过程, ...

最新文章

  1. 好骚气的树状数组的解释
  2. 17_clickhouse分布式集群部署
  3. javaSE各阶段练习题--初识Java章节
  4. 自定义通配器导入bean对象
  5. telnet到设备里 php_金融行业思科设备典型网络故障案例:76系列典型案例(一)...
  6. vb子程序未定义怎么改怎么办_煤粉输送不畅、秤不稳怎么办?多家企业这样改!...
  7. python四舍五入round_四舍五入就用round( )?Python四舍五入的正确打开方式!-Go语言中文社区...
  8. Linux学习总结(73)——Linux高频命令大总结
  9. C++ string字符串的增删改查
  10. 代码没写完,哪里有脸睡觉!17 张程序员壁纸推荐
  11. 图像识别算法超低代码开发方案
  12. linux的dhcp配置命令,Linux下DHCP配置命令
  13. 2010年安全主题展望
  14. (hightopo)学习笔记(1)
  15. 实验报告(LCS算法和背包算法)
  16. python 折线图 excel_如何使用python读取excel数据并绘制折线图
  17. 鸿蒙系统 安卓碎片化,鸿蒙系统讲解决安卓碎片化问题,4G流畅度媲美12G!
  18. 电脑重装Win10 64位系统的方法
  19. 欢迎进入GeekYang博客导航一站式搜索(所有博客的汇总帖)
  20. 兰吉尔FFC3 电表电能量采集终端替代方案(DLMS红外光电采集器)

热门文章

  1. ruby 生成哈希值_如何检查Ruby中是否存在哈希键?
  2. Java生成随机数的4种方式,以后就用它了!
  3. YOLO v3 安装并训练自己数据
  4. JQuery Datatables辅助函数
  5. 独立磁盘冗余阵列:RAID
  6. mfc try catch 捕获并显示_你的异常捕获够优雅不?求你别只会try{...} catch{...}了
  7. 腾讯TIM自动回复内容怎么自定义添加
  8. Windows11电脑锁屏快捷键是什么
  9. 扫一扫闪退的可能性之一[wex5开发]
  10. php需要什么技能,PHP初学者必备的技能