线程池

线程池的基本思想:线程频繁的创建、销毁会极大地占用系统资源,为了减少系统在创建销毁线程时的开销,线程池应运而生。线程池包括多个已创建的线程,当有任务要在新线程中执行时,将任务提交给线程池,线程池选取空闲线程或新开线程执行该任务,可见线程池应维护一个任务队列和线程队列。此外还要对线程最大数、最小数目、空闲等待时间等进行管理。

Executor、ExecutorService接口(线程池)

Executor提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。

方法execute()向线程池提交任务

ExecutorService接口 一个ExecutorService包括运行、关闭、终止三个生命阶段,当一个ExecutorService处于关闭状态时,不能再向线程池提交任务。线程池管理,提交任务功能扩展submit

AbstractExecutorService实现了ExecutorService接口 ,ThreadPoolExecutor、ScheduledThreadPoolExecutor类是具体的线程池实现类。

CompletionService接口、ExecutorCompletionService类

能返回已完成任务,维护一个已完成任务队列(Future),通过take() 函数可以获得任务。

CompletionService接口将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果。

ExecutorCompletionService类 依赖于一个线程池对象Excutor,在一个Excutor基础上维护一个已完成任务队列。

Callable/Runnable、Future(任务接口),

(1)Callable是能够返回结果的可执行任务,Runnable不返回执行结果。文档中说Future 表示异步计算的结果,从CompletionService接口来理解,感觉不如说Future是执行完之后,包含返回结果且可以取消的任务。

(2)execute方法只能提交Runnable任务,ExecutorService接口扩展的submit方法还可以提交Callable任务,ExecutorCompletionService类的submit也支持两种任务

(3)FutrueTask实现了RunnableFuture接口,且可以由一个Callable对象来构造,基本包括了三个接口的功能

Executors(创建线程池)

类提供了用于此包中所提供的执行程序服务的工厂方法。

引用这里

ExecutorCompletionService详解

ExecutorCompletionService源码
    //成员变量,一个执行器,一个存放执行结果的阻塞队列
//一个ExecutorService抽象类(转化submit的Runnable或Callable为RunnableFuture<V>)
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
    //提交待执行的任务,任务均会转化为RunnableFuture<V>接口,然后放入执行器执行。
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
} public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
executor.execute(new QueueingFuture(f));
return f;
}
    //内部类QueueingFuture,将转化后的RunnableFuture<V>接口对象,装配,重写done方法,使得任务执行结束后,放入完成队列
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
    //阻塞方法,直至队列中有任务完成
public Future<V> take() throws InterruptedException {
return completionQueue.take();
} public Future<V> poll() {
return completionQueue.poll();
} public Future<V> poll(long timeout, TimeUnit unit)
throws InterruptedException {
return completionQueue.poll(timeout, unit);
}
阻塞队列take方法源码
    //用到了ReentrantLock,队列为空时await,队列使用put加元素时signal.....好一个PV操作...
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}

总结

ExecutorCompletionService初始化时放入了一个线程池,并且每个submit的任务的执行结果,都会记录到本身的阻塞队列中,重点是,

如果使用take()阻塞方法取出结果的数量等于submit的任务数量,那么所有任务一定是complete(完成)。

代码示例

CompletionService<Integer> completionExecutor=new ExecutorCompletionService<>(Executors.newFixedThreadPool());

List<Task> subTasks=multiTask.getSubTasks();//假设list中有5个任务

//全部submit到ExecutorCompletionService
for (Task task : subTasks) {
completionExecutor.submit( new Runnable() {
public void run() {
task.runTask();
}
}, Integer.valueOf(TASKFINISHED));
} //如果取任务的数量恰好是submit的数量,那么下面这段一定阻塞,直至submit的任务全部完成
for (int i = 0; i < subTasks.size(); i++) {
try {
//阻塞,直至有一个任务完成,并取回结果
Future<Integer> future=completionExecutor.take();
future.get()
} catch (InterruptedException) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

CompletionService/ExecutorCompletionService/线程池/concurrent包的更多相关文章

  1. Python程序中的线程操作(线程池)-concurrent模块

    目录 Python程序中的线程操作(线程池)-concurrent模块 一.Python标准模块--concurrent.futures 二.介绍 三.基本方法 四.ProcessPoolExecut ...

  2. 进程池和线程池 concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor

    import time#线程池可以用shutdown submit from threading import current_thread from concurrent.futures impor ...

  3. python并发编程之进程池,线程池concurrent.futures

    进程池与线程池 在刚开始学多进程或多线程时,我们迫不及待地基于多进程或多线程实现并发的套接字通信,然而这种实现方式的致命缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多, 这会对 ...

  4. 创建进程池与线程池concurrent.futures模块的使用

    一.进程池. 当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量就应该考虑去 限制进程数或线程数,从而保证服务器不会因超载而瘫痪.这时候就出现了进程池和线程池. 二.conc ...

  5. concurrent包分析之Executor框架

    文章目录 线程生命周期的开销:线程比较少的情况使用new Thread(task)无多大影响,但是如果涉及到线程比较多的情况,应用的性能就会受到影响,如果jdbc创建连接一样,new Thead创建线 ...

  6. (11)线程池(最新的concurrent.futures包去开启)

    '''concurrent.futures是最新的开启线程池的包'''import timefrom concurrent.futures import ThreadPoolExecutor #开启线 ...

  7. 【进阶之路】线程池拓展与CompletionService操作异步任务

    大家好,我是练习java两年半时间的南橘,小伙伴可以一起互相交流经验哦. 一.扩展ThreadPoolExecutor 1.扩展方法介绍 ThreadPoolExecutor是可以扩展的,它内部提供了 ...

  8. java多线程管理 concurrent包用法详解

        我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量 ...

  9. java concurrent包的学习(转)

    java concurrent包的学习(转) http://my.oschina.net/adwangxiao/blog/110188 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常 ...

随机推荐

  1. HTML5图形图像处理技术研究

    摘要:图形图像处理平台大部分是传统的C/S架构的桌面应用程序,维护困难,共享性差,而B/S架构的Web程序具有易维护.易共享的优点.本文研究了基于HTML5的Web图形图像处理技术,用HTML5实现了 ...

  2. PHP读取CSV文件把数据插入到数据库,本地没有问题,阿里云测试服务器不行

    原因是 本地windows和服务器linux编码不同,在代码中不要加编码转换的内容,而是把csv文件另存为utf-8文件上传就可以了,windows和Linux都就可以了. html代码: PHP端代 ...

  3. Nginx编译配置杂记

    1.http://nginx.org/download/nginx-1.6.3.tar.gz 2. [root@track nginx-1.6.3]#./configure --prefix=/usr ...

  4. Java 内存管理

    java 内存管理机制 JAVA 内存管理总结 java 是如何管理内存的 Java 的内存管理就是对象的分配和释放问题.(两部分) 分配 :内存的分配是由程序完成的,程序员需要通过关键字 new 为 ...

  5. TAC Beta版本 冲冲冲!!!

    一.Beta版本冲刺博客目录: 第一天 第二天 第三天 第四天 第五天 第六天 第七天 二.Beta版本需要改进完善的功能: service层传入参数的判断与提示以及各函数内的相应提示 界面改进.优化 ...

  6. 深夜重温JavaScript中的对象和数组

    这一块实际上已经学过了,因为没有学好,在工作过程中遇到一些对象或者数组的操作,会去百度查找,浪费了许多宝贵的时间,所以特地再拐过头来重新学习. 对象 基本概念: 对象这种基本的数据结构还有其他很多种叫 ...

  7. 第一次作业——subway

    作业源程序代码:https://github.com/R-81/subway 作业程序使用说明:通过输入命令参数求解路线(仅支持-b,-c),根据参数得出路线后,程序不会结束,此时可输入地铁路线名(例 ...

  8. HTTP超文本传输协议-HTTP/1.1中文版

    摘要 超文本传输协议(HTTP)是一种为分布式,合作式,多媒体信息系统服务,面向应用层的协议.它是一种通用的,不分状态(stateless)的协议,除了诸如名称服务和分布对象管理系统之类的超文本用途外 ...

  9. Java学习笔记12

    循环 打印一个字符串(例如: "Welcome to Java!") 100次,就需要吧下面的输出语句重复写100遍,这是相当繁琐的: System.out.println(&qu ...

  10. jquery实现简单瀑布流布局

    jquery实现简单瀑布流布局 是开头都会说的原理 瀑布流布局有两种,一种是固定列,一种是非固定列.在此主要记述第一种的实现. 固定列的特征是:无论页面如何缩放,每行的总列数都一致. 一行4列的瀑布流 ...