一.Executors创建线程执行器的基本方式及其弊端
1.四种创建执行器方法的简介
java创建线程执行器(Executor接口实现类)时常用以下代码
//合理的首选:CachedThreadPool会在程序执行的时候创建与需要同等数量的线程,回收九线城市停止创建新线程;
ExecutorService executorService= Executors.newCachedThreadPool();
//同名,应该与“定时”相关
ExecutorService executorService=Executors.newScheduledThreadPool(5);
//创建固定数量的线程集处理提交的任务,不用付出创建每个任务的开销。
ExecutorService executorService=Executors.newFixedThreadPool(5);
//类似于线程数量为1的FixThreadPool,若提交了多个任务则人物会排队,即SingleThreadExecutor会序列化其处理的任务。
ExecutorService executorService=Executors.newSingleThreadExecutor();
2.Executors方法创建执行器的弊端
阿里java编程规范并不允许直接用Executors去创建,因为Executors中的newXXXThreadPool()方法实现方式是返回Executor接口实现类,经常是ThreadPoolExecutor或其子类ScheduledThreadPoolExecutor。由于其构造参数是java源码指定,灵活性并不高。
阿里Java编程规范建议使用更细粒度的ThreadPoolExecutor或者ScheduledThreadPoolExecutor去创建线程执行器,这样可以熟悉线程执行器对象创建时的参数细节,规避资源浪费。图1展示了线程池接口Executor及实现类的继承关系:
如图所示。篮圈中使我们一般使用的引用接口类型,大概是因为除了其实现的接口Executor,他还有许多方法可供调用,比如void shutdown()来结束执行器对象接受新的任务。两个实现类ThreadPoolExecutor、ScheduledThreadPoolExecutor是阿里推荐的实现执行器的最小粒度元素。
newFixedThreadPool和newSingleThreadExecutor堆积的请求处理队列可能耗费非常大的内存,甚至OOM(out of memory:内存溢出)。方法源码如下,注意各有其同名重载的实现:
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),//这个参数
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));//最后这个参数
}
newCacheThreadPool和newScheduledThreadPool方法线程最大数是Integer.MAX_VALUE,可能创建非常多的线程,设置造成内存溢出。方法源码如下,注意各有其同名重载的实现:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
二.创建执行器ExecutorService
…待更新