直接上代码

  class LinkedBlockingDequeDemo {
// 循环是否结束的开关
private static volatile boolean flag1 = true;
private static volatile boolean flag2 = true;
// 生成者生产的产品
private static AtomicInteger atomicInteger = new AtomicInteger(1);
//二个 双端阻塞队列
private LinkedBlockingDeque linkedBlockingDeque1;
private LinkedBlockingDeque linkedBlockingDeque2; public LinkedBlockingDequeDemo(LinkedBlockingDeque linkedBlockingDeque1, LinkedBlockingDeque linkedBlockingDeque2) {
this.linkedBlockingDeque1 = linkedBlockingDeque1;
this.linkedBlockingDeque2 = linkedBlockingDeque2;
System.out.println(linkedBlockingDeque1.getClass().getName());
System.out.println(linkedBlockingDeque2.getClass().getName());
} // 生产者
public void producer() throws InterruptedException {
String data = "";
while (flag1) {
data = atomicInteger.getAndIncrement() + "";//这是产品
//TimeUnit.SECONDS.sleep(1);// 1秒生成一个产品
if (Integer.valueOf(data) <= 10) {
//存到 linkedBlockingDeque1 队列中
linkedBlockingDeque1.put(data + "队列1");
System.out.println(Thread.currentThread().getName() + "添加元素到 阻塞队列 linkedBlockingDeque1,成功,元素为: " + data + "队列1");
} else {
//存到 linkedBlockingDeque2 队列中
linkedBlockingDeque2.put(data + "队列2");
System.out.println(Thread.currentThread().getName() + "添加元素到 阻塞队列 linkedBlockingDeque2,成功,元素为: " + data + "队列2");
}
}
} // 消费者
public void consumer1() throws InterruptedException {
while (flag2) {
try {
TimeUnit.MILLISECONDS.sleep(3);
if (!linkedBlockingDeque1.isEmpty()) {
// 自己的队列不为空, 就从自己的队列中取数据消费, 从头开始消费数据
System.out.println(Thread.currentThread().getName() + "从自己队列 Deque1中 的头部消费了一个产品:" + linkedBlockingDeque1.takeFirst());
} else if (!linkedBlockingDeque2.isEmpty()) {
// 如果 另一个队列不为空, 就从他的尾开始消费数据
System.out.println(Thread.currentThread().getName() + "从别人队列 Deque2中 的尾部消费了一个产品:" + linkedBlockingDeque2.takeLast());
} else {
flag2 = false;//这里结束消费
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
}
} public void consumer2() throws InterruptedException {
while (flag2) {
try {
TimeUnit.MILLISECONDS.sleep(3);
if (!linkedBlockingDeque2.isEmpty()) {
// 自己的队列不为空, 就从自己的队列中取数据消费, 从头开始消费数据
System.out.println(Thread.currentThread().getName() + "从自己队列 Deque2中 的头部消费了一个产品:" + linkedBlockingDeque2.takeFirst());
} else if (!linkedBlockingDeque1.isEmpty()) {
// 如果 另一个队列不为空, 就从他的尾开始消费数据
System.out.println(Thread.currentThread().getName() + "从别人队列 Deque1中 的尾部消费了一个产品:" + linkedBlockingDeque1.takeLast());
} else {
flag2 = false;//这里结束消费
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
}
} // 停止生产的方法
public void stop() {
this.flag1 = false;
} public static void main(String[] args) throws InterruptedException {
//工作窃取代码演示: 什么是工作窃取? 在生产者和消费者模型中,
// 每个消费者都对应一个阻塞队列(LinkedBlockingDeque),当消费者当前的队列中的任务消费完了后, 不会就此结束,
// 他会从另一个队列中获取对应的任务来进行消费,
// 这就是 LinkedBlockingDeque的好处,因为他是双端队列,可以从头和尾 来获取元素 /**
*
* 看到的效果就是: 消费者线程1, 从自己的队列Deque1 中, 从头部开始消费1-10, 之后,开始从 别人的队列Deque2中消费产品了
*
* 这里让生产者 1毫秒之后停止生产,然后消费者开始消费
*/
LinkedBlockingDeque<String> linkedBlockingDeque1 = new LinkedBlockingDeque<>();
LinkedBlockingDeque<String> linkedBlockingDeque2 = new LinkedBlockingDeque<>();
LinkedBlockingDequeDemo linkedBlockingDequeDemo = new LinkedBlockingDequeDemo(linkedBlockingDeque1, linkedBlockingDeque2); new Thread(() -> {
try {
linkedBlockingDequeDemo.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "生产者线程").start(); new Thread(() -> {
try {
linkedBlockingDequeDemo.consumer1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "消费者线程1").start(); new Thread(() -> {
try {
linkedBlockingDequeDemo.consumer2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "消费者线程2").start(); TimeUnit.MILLISECONDS.sleep(1);
linkedBlockingDequeDemo.stop();
}
}

运行结果 : 可以看到 线程1,在自己的阻塞队列中消费完之后, 并没有结束,从别人的队列中来 获取任务来执行







JUC 并发编程--10, 阻塞队列之--LinkedBlockingDeque 工作窃取, 代码演示的更多相关文章

  1. JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑

    直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列 public class JucPCdemo03 { /** * 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个 * ...

  2. JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor

    先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码: /** * 这个是 {@link DelayQueue} 延时队列 的验证使用类 */ class MyDelayed ...

  3. JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证

    这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...

  4. Java并发编程:阻塞队列(转载)

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  5. 【转】Java并发编程:阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  6. 12、Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  7. (转)Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  8. java并发编程学习: 阻塞队列 使用 及 实现原理

    队列(Queue)与栈(Stack)是数据结构中的二种常用结构,队列的特点是先进先出(First In First Out),而Stack是先进后出(First In Last Out),说得通俗点: ...

  9. java并发编程:阻塞队列

    一.几种主要的阻塞队列 自从Java 1.5之后,在java.util.concurrent包下提供了若干个阻塞队列,主要有以下几个: ArrayBlockingQueue:基于数组实现的一个阻塞队列 ...

随机推荐

  1. 【python】Leetcode每日一题-132模式

    [python]Leetcode每日一题-132模式 [题目描述] 给定一个整数序列:a1, a2, ..., an,一个132模式的子序列 ai, aj, ak 被定义为:当 i < j &l ...

  2. Kafka Rebalance机制和选举策略总结

    自建博客地址:https://www.bytelife.net,欢迎访问! 本文为博客同步发表文章,为了更好的阅读体验,建议您移步至我的博客 本文作者: Jeffrey 本文链接: https://w ...

  3. composer update -- memory_limit

    compsoer update取消memory_limit限制.取消扩展对于版本的限制 php -d memory_limit=-1 ./composer.phar update --ignore-p ...

  4. mac打开class文件

    本来不想写这个东西的.但是这个却费了我一番周折. 我要先声明一点的是,我从来不讲iOS当成一个单独的系统,而是将这个操作系统归位unix内核的系统. 简单来说,我把它当成linux在用. 但是,mac ...

  5. 谁动了我的 Linux?原来 history 可以这么强大!

    当我们频繁使用 Linux 命令行时,有效地使用历史记录,可以大大提高工作效率. 在平时 Linux 操作过程中,很多命令是重复的,你一定不希望大量输入重复的命令.如果你是系统管理员,你可能需要对用户 ...

  6. Spring Cloud Alibaba(9)---Sentinel概述

    Sentinel概述 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统自适应保护.热点防 ...

  7. 关于ollydbg的堆栈视图的使用(结合crackme2分析)

    在crackme2中我们通过在弹出的窗口处下段然后逐层往用户区回溯,我们利用不断下断点和反复运行程序回溯,其实可以利用Ollydbg的堆栈视图来完成, ollydbg的堆栈视图反映了程序在运行期间函数 ...

  8. [CSS属性设置,盒子模型,网页布局]

    [CSS属性设置,盒子模型,网页布局] CSS属性设置 1. 宽和高 width:属性可以为元素设置宽度. height:属性可以为元素设置高度. 块级标签的宽度不修改的情况下默认占浏览器的一整行,块 ...

  9. pip安装模块或者更新出现问题Error:Could not install packages due to an EnvironmentError

    问题分析 出现此问题大致的原因: 就是包安装的位置没有读写的权限,这个多半是因为安装python的时候安装在了C盘,或者其他programs这类的文件夹里 或者就是环境变量的设置的安装位置的问题,导致 ...

  10. SimpleSelectionSort

    简单选择排序 <script type="text/javascript"> var obj={ data:[0,3,1,5,7,4,8,9,5], length:8 ...