线程复用:线程池

一、为什么需要线程池

为了避免系统频繁地创建和销毁线程,使用线程池让线程进行复用。(即创建线程变成了从线程池中获取空闲线程,销毁线程变成了把线程放回线程池中。)

二、JDK对线程池的支持:Executor框架

一)Excutor框架简介

public static ExecutorService newFixedThreadPool(int Threads) //返回一个固定线程数量的线程池,当新任务提交时无空闲线程,则任务进入等待队列,等待空闲线程。

public static ExecutorService newSingleThreadExecutor() //返回一个只有一个线程的线程池,多余的任务被提交到线程池,会进入等待队列,按先入先出顺序执行。

public static ExecutorService newCahedThreadPool() //返回一个可根据实际情况调整线程数量的线程池

public static ScheduledExecutorService newSingleThreadScheduledExecutor() //线程池中的线程可根据时间执行任务。

public static ScheduledExecutorService newScheduledThreadPool()
public class SESDemo {

    public static void main(String[] args){
ScheduledExecutorService p = Executors.newScheduledThreadPool(10);
p.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(1000);
System.out.println(System.currentTimeMillis()/1000+" and name is "+
Thread.currentThread().getName());
}catch (Exception e){
e.printStackTrace();
}
}
},0,2, TimeUnit.SECONDS);
}
}
/*1504236959 and name is pool-1-thread-1
1504236961 and name is pool-1-thread-1
1504236963 and name is pool-1-thread-2
1504236965 and name is pool-1-thread-1
1504236967 and name is pool-1-thread-3
1504236969 and name is pool-1-thread-2
.......
1504237017 and name is pool-1-thread-7
1504237019 and name is pool-1-thread-7
1504237021 and name is pool-1-thread-7
1504237023 and name is pool-1-thread-7
1504237025 and name is pool-1-thread-7
*/

注意:任务本身不能抛出异常,不然后续所有执行都会被中断。

二)框架内部实现:

以上方法具体实现都使用了ThreadPoolExecutor,它们都封装了ThreadPoolExecutor

其中workQueue指被提交但未被执行的任务队列。

拒绝策略:线程池中的线程已经用完,队列也已经排满。

JDK内置的四种拒绝策略:

AbortPolicy:直接抛出异常,阻止系统正常执行。

CallerRunsPolicy:直接在任务提交的线程内执行线程。

DiscardOledestPolicy:丢弃最老的一个任务,并再次提交当前任务。

DiscardPolicy:丢弃无法处理的当前任务,不做其他处理。

以上策略都实现了RejectedExecutionHandler接口,如果以上策略无法满足我们的需求,我们可以扩展该接口。

public class RejectThreadPoolDemo {
public static class MyTask implements Runnable{
@Override
public void run() {
System.out.println(System.currentTimeMillis()+" :Thread ID:"+
Thread.currentThread().getId()); try{
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
} public static void main(String[] args) throws InterruptedException {
MyTask myTask=new MyTask();
ThreadPoolExecutor es = new ThreadPoolExecutor(5, 5, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10)
, Executors.defaultThreadFactory(),
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println(r.toString() + "is discard");
}
}); for (int i=0;i<Integer.MAX_VALUE;i++){
es.submit(myTask);
Thread.sleep(10);
}
}
}

三)自定义线程创建

线程池中线程的来源:ThreadFactory接口。override该接口中的

public Thread newThread(Runnable r);

方法即可。

四)扩展线程池

ThreadPoolExecutor是个可以扩展的线程池接口,它提供了beforeExecutor(),afterExecutor()和terminated三个接口对线程池进行控制。

public class ExtThreadPool {

    public static class Mytask implements Runnable{
private String name; public Mytask(String name) {
this.name = name;
} @Override
public void run() {
System.out.println("正在执行:线程ID"+Thread.currentThread().getId()+
"任务名:"+name);
}
} public static void main(String[] args) throws InterruptedException {
ExecutorService es=new ThreadPoolExecutor(5,5,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()){ @Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("准备执行:"+((Mytask)r).name);
} @Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("执行完毕:"+((Mytask)r).name);
} @Override
protected void terminated() {
System.out.println("线程池退出");
}
}; for (int i=0;i<5;i++){
Mytask mytask=new Mytask("task"+i);
es.execute(mytask);
Thread.sleep(10);
} es.shutdown(); //所有任务执行完毕后,关闭线程池。
}
}

五)线程池中寻找异常堆栈

解决多线程中幽灵般的异常:

方法一:放弃submit()改用execute()

方法二:extends ThreadPoolExecutor

六)分而治之,Fork/Join框架

分阶段对大量数据进行处理,然后对结果进行整合。

互助精神:

重要接口:

public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)

ForkJoinTask两个重要子类:

Java并发程序设计(五)JDK并发包之线程复用:线程池的更多相关文章

  1. Java并发程序设计(一) 基础概念

    Java并发程序设计(一) 基础概念 一.必须知道的几个概念 一)同步(Synchronous)和异步(Asynchronous) 同步:同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后 ...

  2. 和朱晔一起复习Java并发(五):并发容器和同步器

    本节我们先会来复习一下java.util.concurrent下面的一些并发容器,然后再会来简单看一下各种同步器. ConcurrentHashMap和ConcurrentSkipListMap的性能 ...

  3. Java并发程序设计(四)JDK并发包之同步控制

    JDK并发包之同步控制 一.重入锁 重入锁使用java.util.concurrent.locks.ReentrantLock来实现.示例代码如下: public class TryReentrant ...

  4. Java并发(五):synchronized实现原理

    一.synchronized用法 Java中的同步块用synchronized标记. 同步块在Java中是同步在某个对象上(监视器对象). 所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操 ...

  5. Java并发:五种线程安全类型、线程安全的实现、枚举类型

    1. Java中的线程安全 Java线程安全:狭义地认为是多线程之间共享数据的访问. Java语言中各种操作共享的数据有5种类型:不可变.绝对线程安全.相对线程安全.线程兼容.线程独立 ① 不可变 不 ...

  6. Java并发程序设计(二)Java并行程序基础

    Java并行程序基础 一.线程的生命周期 其中blocked和waiting的区别: 作者:赵老师链接:https://www.zhihu.com/question/27654579/answer/1 ...

  7. 【Java并发编程五】信号量

    一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...

  8. Java并发(五)线程池使用番外-分析RejectedExecutionException异常

    目录 一.入门示例 二.异常场景1 三.异常场景2 四.解决方法 之前在使用线程池的时候,出现了 java.util.concurrent.RejectedExecutionException ,原因 ...

  9. Java并发程序设计(九)设计模式与并发之不变模式

    设计模式与并发之不变模式 使用不变模式的目的:除去多线程中的同步操作,提高并行程序的性能. 一个类在的内部状态创建后,在整个生命周期内都不会发生改变,该类就是不变类. /** * @author: T ...

随机推荐

  1. android摄像头(camera)之 v4l2的c测试代码【转】

    转自:https://blog.csdn.net/ldswfun/article/details/8745577 在移植android hal的过程中,移植的首要任务是要确保驱动完好,camera是属 ...

  2. linux源码Makefile详解(完整)

    转自:http://www.cnblogs.com/Daniel-G/p/3286614.html 随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 ...

  3. 『转载』hadoop2.x常用端口、定义方法及默认端口

    『转载』hadoop2.x常用端口.定义方法及默认端口 1.问题导读 DataNode的http服务的端口.ipc服务的端口分别是哪个? NameNode的http服务的端口.ipc服务的端口分别是哪 ...

  4. CentOS7 虚拟机设置文件共享 VMWareTools安装遇到的坑

    设置文件共享的前提条件是已经安装好VMware Tools. 现在从安装VMware Tools开始讲起: 第一步:安装VMware Tools (如果安装的centos是最小安装,需要提前安装组件g ...

  5. centos6.5环境下zookeeper-3.4.6集群环境部署及单机部署详解

    centos6.5环境下Zookeeper-3.4.6集群环境部署 [系统]Centos 6.5 集群部署 [软件]准备好jdk环境,此次我们的环境是open_jdk1.8.0_101 zookeep ...

  6. Uiautomator之入门

    优点:1.可以对所有操作进行自动化,操作简单: 2.不需要对被测程序进行重签名,且,可以测试所有设备上的程序,比如~某APP,比如~拨号,比如~发信息等等    3.对于控件定位,要比robotium ...

  7. 每天一个linux命令:scp命令

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...

  8. spring mvc 校验@NULL

    一需要的包 1 validation-api-1.0.0.GA.jar:JDK的接口: 2 hibernate-validator-4.2.0.Final.jar 是对上述接口的实现: 二 若在pom ...

  9. 【ES】学习3-请求体查询

    1.空查询 GET /index_2014*/type1,type2/_search {} GET /_search { , } 2.查询表达式 DSL只需将查询语句传递给 query 参数 GET ...

  10. python 全栈开发,Day73(django多表添加,基于对象的跨表查询)

    昨日内容回顾 多表方案: 如何确定表关系呢? 表关系是在2张表之间建立的,没有超过2个表的情况. 那么相互之间有2条关系线,先来判断一对多的关系. 如果其中一张表的记录能够对应另外一张表的多条记录,那 ...