java线程基础巩固---线程生产者消费者的综合实战结合Java8语法
基于上一次【http://www.cnblogs.com/webor2006/p/8909558.html】学习的多个生产者与多个消费者模型,此次用另外一个案例来进一步巩固线程之间的调度处理,这里还是以之前【http://www.cnblogs.com/webor2006/p/7895410.html】举过的信息采集功能为例:有若干台采集服务器,然后还有一台主机,这台主机需要等待这若干台服务器信息采集完之后再做进一步的处理,一台采集服务器就对应一个线程,如之前写的代码:

但是假如有成千上万台那怎么办,不可能每台服务器对应一个线程,因为线程是有一个stackSize的上限滴,此时就需要用到线程同步来避勉这个问题了,比如:最大工作线程数就是5个,然后当超过5个的时候其它的工作线程都会进行wait()释放出cpu执行权,待有一个工作线程执行完了则通知wait()的其它线程加入工作队列,大体思路是这样,下面来看一下如何具体执行,这里采用Java8的语法来编写,毕境之前学习过练练手:
首先创建十个线程,这里采用流的方式来创建,如下:

好,具体线程的执行代码这里先放一放,先将框架代码编写好,因为需要等待每个线程的执行完成再执行,所以此时需要用到join()方法了,如下:

所以此时应该用一个集合将所有启动的线程给缓存下来,但是对于Java8中的Stream.forEach()方法是一个teminal operation,执行完流操作就结束了,所以这里定义一个集合变量准备来缓存一下:

然后接下来就可以进行join()总的操作了,如下:

好了~~框架搭建完毕!接下来就得将重心放在线程的具体执行这块了,如下:

接着线程执行前先要来判断是否工作线程数已经超过5个了,如果超过那其它所有线程都得wait()了,而如何判断工作线程总数呢?这里需要用一定的技巧,这里就不卖关子了,贴出来细细体会:
public class CaptureService {
private static final int MAX_WORKER = 5;
private static final LinkedList<CaptureService.Control> CONTROLS = new LinkedList<>();//代表总的工作线程
public static void main(String[] args) {
List<Thread> worker = new ArrayList<>();
Arrays.asList("M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10").stream()
.map(CaptureService::createCaptureThread)
.forEach(t -> {
t.start();//启动每一个线程
worker.add(t);
});
worker.stream().forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Optional.of("All of capture work finished").ifPresent(System.out::println);
}
private static Thread createCaptureThread(String name) {
return new Thread(() -> {
Optional.of("The worker [" + Thread.currentThread().getName() + "] BEGIN capture data").ifPresent(System.out::println);
synchronized (CONTROLS) {
while (CONTROLS.size() > MAX_WORKER) {
try {
Optional.of("The worker [" + Thread.currentThread().getName() + "] WAIT..").ifPresent(System.out::println);
CONTROLS.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
CONTROLS.addLast(new CaptureService.Control());
}
}, name);
}
private static class Control {
//nothing to do,just a tag
}
}
而如果不满足wait()条件的那当然就得正常工作喽,如下:

而当一个线程任务执行完,则需要通知其它还在wait()住的线程叫他们赶紧加入工作队列中,如下:

另外还得注意咱们是按先进先出的原则来添加tag的,如下:

好,至此代码写完,看一下运行结果:


java线程基础巩固---线程生产者消费者的综合实战结合Java8语法的更多相关文章
- Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例
Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- java线程之多个生产者消费者
温故一下上一节所学习的生产者消费者代码: 两个线程时: 通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者.一个消费者交替执行的功能 类名:ProducterConsumerDem ...
- 基于线程池的线程管理(BlockingQueue生产者消费者方式)实例
1.线程池管理类: public class ThreadPoolManager { private static ThreadPoolManager instance = new ThreadPoo ...
- python进阶:Python进程、线程、队列、生产者/消费者模式、协程
一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...
- java线程基础巩固---线程间通信快速入门,使用wait和notify进行线程间的数据通信
之前已经对于线程同步相关的知识点进行了详细的学习,这次来学习一下线程间的通信相关的知识,话不多说直接用代码进行演练,以一个简陋的生产者消费者模型来初步了解下线程间通信是怎么一回事. 生产消费者第一版: ...
- java线程基础巩固---线程生命周期以及start方法源码剖析
上篇中介绍了如何启动一个线程,通过调用start()方法才能创建并使用新线程,并且这个start()是非阻塞的,调用之后立马就返回的,实际上它是线程生命周期环节中的一种,所以这里阐述一下线程的一个完整 ...
- Java并发基础:线程的创建
线程的创建和管理: 1.应用Thread类显式创建.管理线程 2.应用Executor创建并管理线程. 定义任务: 无返回的任务:实现Runnable接口并编写run()方法. 有响应的任务:实现Ca ...
- Java多线程之并发协作生产者消费者设计模式
两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...
随机推荐
- jupyterlab部署到docker
操作环境:mac OS 10.14.6 docker版本:10.03.1 终端:iterm2 3.3 时间:2019年8月 ::说明::jupyter没有提供单独的jupyterlab镜像,可以使用j ...
- pig-csm 7.9修改记录
PigCms\Lib\Action\System\UsersAction.class.php 存在页面广告跳转 bbs.go _pe.cn的问题 tpl\Home\weimob\public_head ...
- c++ static_cast和dynamic_cast详解
注:从图中可以看出,派生类不仅有自己的方法和属性,同时它还包括从父类继承来的方法和属性.当我们从派生类向基类转换时,不管用传统的c语言还是c++转换方式都可以百分百转换成功.但是可怕是向下转换类型,也 ...
- ZOJ Problem Set - 1003
1.翻译参考 http://www.cnblogs.com/woodfish1988/archive/2006/11/10/556926.html 2.代码参考 http://www.cnblogs. ...
- Appendix 2- Lebesgue integration and Reimann integration
Lebesgue integration and Reimann integration: Reimann: Split up the axis into equal intervals, then ...
- dev控件学习笔记之----CxGrid2
一.cxgrid 表格自适应列宽和增加注脚注和 for i := 0 to ado_lxr_cx.FieldCount - 1 do begin //如果是数字,则注脚求合 ...
- Linux Pycharm 添加图标到root账户桌面
1. 去官网下载pycharm程序 2. 解压缩下载到的tar包 3. 在/usr/share/applications目录下新建一个pycharm.desktop, 写入内容如下, 注意红色字体需要 ...
- idea的配置文件------application.properties和application.yml
当application.yml 和 application.properties 两个文件同时存在的时候,application.properties的优先级是高于application.yml的, ...
- PAT A1020 Tree Traversals(25)
题目描述 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder ...
- Linux就该这么学——新手必须掌握的命令之文件目录管理命令组
touch命令 用途 : 用于创建空白文件或设置文件的时间 格式 : touch [选项] [文件] 参数 作用 -a 仅修改”读取时间”(atime) -m 仅修改”修改时间”(mtime) -d ...