JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑
直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列
public class JucPCdemo03 {
/**
* 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个
* 且,不使用 synchronized 和 lock锁
*/
private volatile boolean flag = true;
private static AtomicInteger atomicInteger = new AtomicInteger(0);
private BlockingQueue<String> blockingQueue;
public JucPCdemo03(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
//生产方法
public void producer() throws InterruptedException {
String data = null;
boolean result;
while(flag){
data = atomicInteger.incrementAndGet()+"";
result = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
if(result){
System.out.println(Thread.currentThread().getName() + "--生产者--添加队列成功--data:" + data);
}else{
System.out.println(Thread.currentThread().getName() + "--生产者--超出等待时间, 退出等待");
}
//我在这里有疑惑? : 你能帮我解决么?
// 这里睡1秒,不能少,因为 atomicInteger加1的操作是原子的,加入阻塞队列的操作是并发的,会导致同一时间内,有多个元素加入到了阻塞队列中,返回都是true,即使规定阻塞队列容量为1,
// 所以这里的疑惑是: 阻塞队列容量为1, 并发情况下,却多个数据都加入队列成功了?为什么
TimeUnit.SECONDS.sleep(1);
}
System.out.println();
System.out.println();
System.out.println();
System.out.println("生产者停止生产了");
}
//消费方法
public void consumer() throws InterruptedException {
String data = null;
while(flag){
data = blockingQueue.poll(2, TimeUnit.SECONDS);
if(null == data || "".equals(data)){
System.out.println(Thread.currentThread().getName() + "--消费者--超出等待时间.退出等待,消费停止");
flag = false;
return;
}else{
System.out.println(Thread.currentThread().getName() + "--消费者--消费成功,消费的数据为: data:" + data);
}
}
System.out.println();
System.out.println();
System.out.println();
System.out.println("消费者停止消费了");
}
public void stop(){
flag = false;
}
public static void main(String[] args) throws InterruptedException {
JucPCdemo03 jucPCdemo03 = new JucPCdemo03(new ArrayBlockingQueue<>(1));
new Thread(()->{
try {
jucPCdemo03.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"生产者线程启动").start();
new Thread(()->{
try {
jucPCdemo03.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"消费者线程启动").start();
TimeUnit.SECONDS.sleep(5);
jucPCdemo03.stop();
}
}
运行结果:

如果把生产者的 睡一秒, 注释掉, 会是另一种结果, 生产者生产的data 都很大,是因为一直再while循环中,不停的自增, 但是同时3个数据加入队列成功,可是队列的容量设置是1啊, 这个结果让我有些疑惑, 你能帮我解惑么?

后来想到: 阻塞队列类本身是juc包下的, 肯定是原子性操作的, 所以他的容量前后都是始终为1, 是因为 "生产者线程启动--生产者--添加队列成功--data:269209" 这句话打印,这里并发打印了, 所以给我看到的假象多个数据都加入阻塞队列成功了, 于是验证: 加一行代码,

运行结果为: 队列容量始终为1, "生产者线程启动--生产者--添加队列成功--data:269209" 这句话有时候打印三次,有时候打印一次,很明显验证了我的结论

JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑的更多相关文章
- 用阻塞队列实现一个生产者消费者模型?synchronized和lock有什么区别?
多线程当中的阻塞队列 主要实现类有 ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序 LinkedBlockingQueue是一个基于链表结构的 ...
- JUC 并发编程--10, 阻塞队列之--LinkedBlockingDeque 工作窃取, 代码演示
直接上代码 class LinkedBlockingDequeDemo { // 循环是否结束的开关 private static volatile boolean flag1 = true; pri ...
- JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor
先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码: /** * 这个是 {@link DelayQueue} 延时队列 的验证使用类 */ class MyDelayed ...
- JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证
这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...
- java并发编程:阻塞队列
一.几种主要的阻塞队列 自从Java 1.5之后,在java.util.concurrent包下提供了若干个阻塞队列,主要有以下几个: ArrayBlockingQueue:基于数组实现的一个阻塞队列 ...
- Java并发编程:阻塞队列(转载)
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- 【转】Java并发编程:阻塞队列
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- Java并发编程:阻塞队列 <转>
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- 12、Java并发编程:阻塞队列
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
随机推荐
- Host头部攻击
在HTTP的请求报文中,我们经常会看到Host字段,如下 GET /test/ HTTP/1.1 Host: www.baidu.com Connection: keep-alive Upgrade- ...
- nodejs-模块系统
Node.js模块系统 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统. 模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的.换言之,一个 Node. ...
- Day001 基本的Dos命令
基本的Dos命令 打开cmd的方式 开始+系统+命令提示符(有时候需要右键以管理员身份运行) Win+R键,输入cmd打开控制台 按住shift键的同时鼠标右键,点击在此处打开powershell窗口 ...
- 从执行上下文(ES3,ES5)的角度来理解"闭包"
目录 介绍执行上下文和执行上下文栈概念 执行上下文 执行上下文栈 伪代码模拟分析以下代码中执行上下文栈的行为 代码模拟实现栈的执行过程 通过ES3提出的老概念-理解执行上下文 1.变量对象和活动对象 ...
- Vue.js源码解析-从scripts脚本看vue构建
目录 1. scripts 脚本构建 1.1 dev 开发环境构建过程 1.1.1 配置文件代码 1.1.2 如何进行代码调试? 1.2 build 生产环境构建过程 1.2.1 scripts/bu ...
- 利用实体bean对象批量数据传输处理
利用实体bean对象批量数据传输处理 需求 现在有两方数据库表结构相同,一方A.另一个方B,现想从A处查询出多个表的数据,传输到B地保存起来. 解决方案1 最简单粗暴的方法就是,查询出A处相关表的数据 ...
- [MySQL数据库之记录的详细操作:增、改、删、单表查询、多表查询]
[MySQL数据库之记录的详细操作:增.改.删.单表查询.多表查询] 记录详细操作 增.删.改 增: insert t1(字段1,字段2,字段3) values (值1,值2,值3), (值1,值2, ...
- [DB] MapReduce
概述 大数据计算的核心思想:移动计算比移动数据更划算 MapReduce既是一个编程模型,又是一个计算框架 包含Map和Reduce两个过程 终极目标:用SQL语句分析大数据(Hive.SparkSQ ...
- Canal和Otter讨论二(原理与实践)
上次留下的问题 问题一: 跨公网部署Otter 参考架构图 解析 a. 数据涉及网络传输,S/E/T/L几个阶段会分散在2个或者更多Node节点上,多个Node之间通过zookeeper进行协同工 ...
- 攻防世界(十三)unserialize3
攻防世界系列 :unserialize3 1.打开题目,反序列化 2.代码审计 类xctf被调用时_weakeup()函数会被自动执行,但当序列化字符串中属性值个数大于属性个数,就会导致反序列化异常, ...