简介
newCachedThreadPool()创建的线程池的特性是:
自动回收不使用的线程(终止并从缓存中移除那些已有 60 秒钟未被使用的线程),(在无可用线程的情况下)自动的为新来的task创建新线程。
使用场景:
在小任务量,任务时间执行短的场景下能提高性能。
在jdk api中的介绍如下一部分,其他的请查看api文档
ThreadPoolExecutor是一个一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置。
线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。
为了便于跨大量上下文使用,此类提供了很多可调整的参数和扩展钩子 (hook)。但是,强烈建议程序员使用较为方便的 Executors 工厂方法构建服务:
1. Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)
2. Executors.newFixedThreadPool(int)(固定大小线程池)
3. Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。
本章使用心得newCachedThreadPool()
- 使用Executors来构建预置服务。
- 要记得使用shutdown() 来关闭执行器,如果不关闭,则一直等待新任务的到来,该方法在api中的解释:按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。如果已经关闭,则调用没有其他作用。
上手使用伪代码:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); //创建线程池执执行器服务
executor.execute(task); //把Runnable交给执行器执行
executor.shutdown(); //申请关闭执行器
简单的示例示例
场景描述:以下示例就是演示了,把一组线程交给执行器执行,在执行器中打印执行器中线程池中的一些任务信息。
/**
* Created by zhuqiang on 2015/8/24 0024.
*/
public class Client {
public static void main(String[] args) throws InterruptedException {
Service s = new Service();
for (int i = 0; i < 3; i++) {
Task task = new Task(new Date(), "task" + i);
TimeUnit.SECONDS.sleep(3); // 休眠3秒,以便等待有任务执行完的线程。在信息里面能看到更丰富的 执行器的管理信息
s.executorTask(task);
}
s.endService(); // 1 如果注释此代码,本程序将挂起。不会结束
}
}
/** 模拟任务类*/
class Task implements Runnable{
private Date initDate; //初始化时间
private String name; //任务名称
public Task(Date initDate, String name) {
this.initDate = initDate;
this.name = name;
}
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.printf(" start-------------%s,任务名称:%s,时间:%s\n", t.getName(),this.name,initDate);
try {
long time = (long)(Math.random() * 10); //模拟工作时间
TimeUnit.SECONDS.sleep(time);
System.out.printf(" end-------------%s,任务名称:%s,耗时:%s\n", t.getName(),this.name,time);
}catch (Exception e){
e.printStackTrace();
}
}
}
/** 服务类,接收每一个任务*/
class Service{
private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
/** 接受任务,直接丢给了 线程池执行*/
public void executorTask(Task task){
System.out.println("service:接收了一个task");
executor.execute(task);
System.out.printf("service:pool执行器中线程中实际的线程数量:%d,执行器中正在执行任务的线程数量:%d,执行器中已经完成的任务数量:%d\n",executor.getPoolSize(),executor.getActiveCount(),executor.getCompletedTaskCount());
}
/** */
public void endService(){
System.out.printf("service-----------------shutdown--------------:pool执行器中线程中实际的线程数量:%d,执行器中正在执行任务的线程数量:%d,执行器中已经完成的任务数量:%d\n",executor.getPoolSize(),executor.getActiveCount(),executor.getCompletedTaskCount());
executor.shutdown();
}
}
某一次的运行结果:
service:接收了一个task
start-------------pool-1-thread-1,任务名称:task0,时间:Mon Aug 24 22:33:23 CST 2015
service:pool执行器中线程中实际的线程数量:1,执行器中正在执行任务的线程数量:1,执行器中已经完成的任务数量:0
service:接收了一个task
service:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:2,执行器中已经完成的任务数量:0
start-------------pool-1-thread-2,任务名称:task1,时间:Mon Aug 24 22:33:26 CST 2015
end-------------pool-1-thread-1,任务名称:task0,耗时:4
service:接收了一个task
service:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:1,执行器中已经完成的任务数量:1
start-------------pool-1-thread-1,任务名称:task2,时间:Mon Aug 24 22:33:29 CST 2015
service-----------------shutdown--------------:pool执行器中线程中实际的线程数量:2,执行器中正在执行任务的线程数量:2,执行器中已经完成的任务数量:1
end-------------pool-1-thread-2,任务名称:task1,耗时:4
end-------------pool-1-thread-1,任务名称:task2,耗时:9
结果说明
仔细看上面的线程名称,和task名称,可以看出来,3个任务只使用了2个线程。如果在更多的任务中,线程得到了复用。性能更好了
可以看到上面打印的信息。一些api打印出来的线程池中的一些任务信息。 没什么可说,先上手。再深入