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多线程之并发协作生产者消费者设计模式
两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...
随机推荐
- JSX AS DSL? 写个 Mock API 服务器看看
这几天打算写一个简单的 API Mock 服务器,老生常谈哈?其实我是想讲 JSX, Mock 服务器只是一个幌子. 我在寻找一种更简洁.方便.同时又可以灵活扩展的.和别人不太一样的方式,来定义各种 ...
- TPM大端模式
1. Big-Endian(BE)大端模式 数据是按照,“高字节.低存储”,即高字节存储在低地址,符合人们直观感受 2. Little-Endian(LE)小端模式 数据是按照,“低字节,低存储”,即 ...
- 【VS开发】【Live555-rtsp】RTSP服务器实例live555源代码分析
原文地址:RTSP服务器实例live555源代码分析作者:mozheer 1. RTSP连接的建立过程 RTSPServer类用于构建一个RTSP服务器,该类同时在其内部定义了一个RTSPClient ...
- 【VS开发】RIbbon编程
多彩界面,Ribbon编程 Ribbon是类似于office2007样式的界面,它替代了传统的MFC程序里的菜单和工具栏,MFC默认生成的Ribbon功能少,需要我们自己添加一些控件和图片等元素使界面 ...
- Centos7 + nginx 托管 Django 项目
使用nginx托管django服务的原理 使用uwsgi开启django服务(通过配置文件启动) 防火墙关闭uwsgi端口(uwsgi的websocket一定要使用127.0.0.1的方式配置)) 编 ...
- C#与C++的区别
C# 参考链接:https://www.runoob.com/csharp/csharp-tutorial.html ------------------C#数据类型----------------- ...
- Linux试题亿点点
1. 在登录Linux时,一个具有唯一进程ID号的shell将被调用,这个ID是什么(b) A.NID B.PID C.UID C.CID # process ID 进程id号 # UID 用户iD号 ...
- paramiko-ssh-秘钥认证实例
import paramiko private_key = paramiko.RSAKey.from_private_key_file('id_rsa.txt') #创建ssh对象 ssh =para ...
- 植物大战僵尸:寻找阳光掉落Call调用
实验目标:通过遍历阳光产生的时间,寻找阳光产生的本地Call,使用代码注入器注入,自定义生成阳光 阳光CALL遍历技巧: 进入植物大战僵尸-> 当出现阳光后->马上搜索未知初始数值 返回游 ...
- Django模板(Template)系统
Django模板系统 官方文档 常用语法 只需要记两种特殊符号: {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 {{ 变量名 }} 变量名由字母数字和下划线组成. 点 ...