基于上一次【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语法的更多相关文章

  1. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

  2. Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量

    Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程:    1.线程是一堆指令,是操作系统调度 ...

  3. java线程之多个生产者消费者

    温故一下上一节所学习的生产者消费者代码: 两个线程时: 通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者.一个消费者交替执行的功能 类名:ProducterConsumerDem ...

  4. 基于线程池的线程管理(BlockingQueue生产者消费者方式)实例

    1.线程池管理类: public class ThreadPoolManager { private static ThreadPoolManager instance = new ThreadPoo ...

  5. python进阶:Python进程、线程、队列、生产者/消费者模式、协程

    一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...

  6. java线程基础巩固---线程间通信快速入门,使用wait和notify进行线程间的数据通信

    之前已经对于线程同步相关的知识点进行了详细的学习,这次来学习一下线程间的通信相关的知识,话不多说直接用代码进行演练,以一个简陋的生产者消费者模型来初步了解下线程间通信是怎么一回事. 生产消费者第一版: ...

  7. java线程基础巩固---线程生命周期以及start方法源码剖析

    上篇中介绍了如何启动一个线程,通过调用start()方法才能创建并使用新线程,并且这个start()是非阻塞的,调用之后立马就返回的,实际上它是线程生命周期环节中的一种,所以这里阐述一下线程的一个完整 ...

  8. Java并发基础:线程的创建

    线程的创建和管理: 1.应用Thread类显式创建.管理线程 2.应用Executor创建并管理线程. 定义任务: 无返回的任务:实现Runnable接口并编写run()方法. 有响应的任务:实现Ca ...

  9. Java多线程之并发协作生产者消费者设计模式

    两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...

随机推荐

  1. 企业证书发布app到七牛云服务

    ---恢复内容开始--- 最近在做企业证书发布app,从申请企业证书,到测试程序发布到七牛云存储.整了几天终于实现了,整理一下资料. 1.首先,申请企业证书. 到苹果开发网站申请企业证书 https: ...

  2. GitHub项目精选(持续更新)

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190815110442972.jpg?x-oss-process=image/watermark,type_Zm ...

  3. JS动态添加的标签无法绑定事件解决方案~~~

    今天用ajax实现动态插入数据时发现监听一直不起作用,一样的代码,非动态的就可以监听实现 这是困扰了我近一个小时的bug,后面才理解到可能是动态插入导致的! 看了看网上的解决方案,似乎都不太通俗,讲的 ...

  4. Prefix to Infix Conversion

    Infix : An expression is called the Infix expression if the operator appears in between the operands ...

  5. 详解vue 路由跳转四种方式 (带参数)

    详解vue 路由跳转四种方式 (带参数):https://www.jb51.net/article/160401.htm 1.  router-link ? 1 2 3 4 5 6 7 8 9 10 ...

  6. Flask_入门

    django是个大而全的框架,flask是一个轻量级的框架. django内部为我们提供了非常多的组件:orm / session / cookie / admin / form / modelfor ...

  7. Centos7 系统启动docker报错 inotify add watch failed

    环境说明: 最近新装的系统启动docker报错,之前没有遇到过.(之前都是系统直接启动,新装机器无报错的情况) 当时排查了很久没找到问题在哪,观察报错信息如下: 提示表文件失败,没有这个文件或者目录. ...

  8. HTML——form表单中常用标签 form input (text hidden password radio checkbox reset submit ) select(option)总结

    <form action="" method="get"> <!-- placeholder="请输入文本" 显示提示 r ...

  9. asp.net 7.分页

    分页 SQL: select * from( select *,row_number()over(order by id) as num from T_userInfo) as t 数据层(UserI ...

  10. linux mysql-5.7.26 安装全记录

    买了个阿里云,自己折腾一下. 时间:2019年7月17日13:40:18 1.下载 wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7. ...