网上关于线程池的文章比比皆是,自己再写,只为了加深印象。也是对自己学过的东西做一下简单的总结。
引子
在Android里面写的线程池,弹出这样的提示,说明有更好的写法。
阿里的 Java开发手册,上面有线程池的一个建议:
线程池不允许使用 Executors 去创建,而是通过
ThreadPoolExecutor
的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors 各个方法的弊端:
1)newFixedThreadPool 和 newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。
2)newCachedThreadPool 和 newScheduledThreadPool:
主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。
ThreadPoolExecutor
先看看如何使用ThreadPoolExecutor创建线程池:
public
ThreadPoolExecutor
(
int
corePoolSize,
int
maximumPoolSize,
long
keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize - 线程池核心池的大小。
maximumPoolSize - 线程池的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 的时间单位。
workQueue - 用来储存等待执行任务的队列。
threadFactory - 线程工厂。
handler - 拒绝策略。
Executors工厂方法:
让我们再看看Executors提供的那几个工厂方法。
newSingleThreadExecutor
创建一个单线程的线程池
。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。
此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newFixedThreadPool
创建固定大小的线程池。
每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newCachedThreadPool
创建一个可缓存的线程池
。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。
此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
这么看来,其实ExecutorService exec1 = Executors.newSingleThreadExecutor();
已经是
是通过
ThreadPoolExecutor
的方式创建,不过正如最上面的图片中显示的,建议手动创建。那么我们就手动创建一个:
/**
* 生成一个无界的并使用缓存的ThreadPoolExecutor
*/
public static ExecutorService newCachedThreadPool() {
ThreadFactory factoryName = new PriorityThreadFactory("thread-tcp", android.os.Process.THREAD_PRIORITY_BACKGROUND);
return new ThreadPoolExecutor(2, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),factoryName);
}
红色部分是自定义线程名字,Java中也可以利用org.apache.commons.lang3写成:
ThreadFactory tf = new BasicThreadFactory.Builder().namingPattern("自定义").daemon(true).build();
至此,完成。