直接上代码

  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. 逆向 time.h 函数库 time、gmtime 函数

    0x01 time 函数 函数原型:time_t time(time_t *t) 函数功能:返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位.如果 se ...

  2. Windows核心编程 第26章 窗口消 息

    窗 口 消 息 Wi n d o w s允许一个进程至多建立10 000个不同类型的用户对象(User object):图符.光标.窗口类.菜单.加速键表等等.当一个线程调用一个函数来建立某个对象时, ...

  3. 哈希爆破神器Hashcat的用法

    目录 HashCat HshCat的使用 使用Hashcat生成字典 使用Hashcat破解NTLMv2 HashCat HashCat系列软件在硬件上支持使用CPU.NVIDIA GPU.ATI G ...

  4. dependencyManagement 版本管理

    帮别人解决bug的时候碰到,随便记录一下. 使用<dependencyManagement>标签, 做版本管理的时候,需要父子项目关联,就需要子模块中利用<parent> 否则 ...

  5. ruby基础(三)

    类和模块 1.类 类是面向对象中一个重要的术语.我们可以把类看作是对象的抽象, 所有的这类对象都有这些特征.而对象则是类的具体实现,按照类的要求创建的 对象就是该类的对象.类就像对象的雏形一样,决定了 ...

  6. R语言执行脚本的几种命令

    R CMD BATCH 和 Rscript 使用前都要先添加环境变量 把 C:\Program Files\R\R-3.3.0\bin; 加到"系统变量"的Path 值的最开始 可 ...

  7. 史上最全(全平台)docker安装方法!

    代码狂魔 32019.01.05 22:46:46字数 4,426阅读 9,949 image.png 2017年2月8日,docker更新到1.13.1(更新日志),此后又分为了docker CE( ...

  8. 【转载】ltp压力测试结果分析脚本

    博客园 首页 新随笔 联系 管理 订阅 随笔- 8  文章- 0  评论- 0  ltp压力测试结果分析脚本   最近工作性质发生了改变,在做操作系统方面的测试.接手的第一个任务是做ltp stres ...

  9. 云计算OpenStack核心组件---cinder存储服务(10)

    一.cinder介绍 1.Block Storage 操作系统获得存储空间的方式一般有两种: (1)通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系统: ...

  10. Java 单例模式:懒加载(延迟加载)和即时加载

    引言 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制(或懒加载.延时加载),也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这 ...