上一节并发编程系列(1)- 线程池原理 已经初步介绍线程池的原理、线程池的创建,但是实际在项目中应该如何使用线程池呢?
一、使用场景介绍
当遇到重复性、且互相无依赖的任务的时候,可以用多线程来实现。
比如:上传多个文件、解析多个文件等等,这些行为相互之间不会影响(即一个任务不依赖与另一个任务的执行成功与否,也不依赖于其执行的结果)。
如果任务执行相互依赖,那么可以用异步去实现。
二、代码实战
下面用一个简单的例子来熟悉下线程池的使用。
1、线程池工厂类-用于创建合适的线程池:
首先创建一个FILE_EXECUTOR,用于创建多线程读取文件的线程池。
(注意:在实际项目开发中,要注意线程池隔离,即不同作用的线程池需要单独定义,我这里有个读取文件任务的线程池,定义为FILE_EXECUTOR;若有上传文件的,可以再定义一个UPLOAD_EXECUTOR)。
不同线程池因任务类型的不同,参数设置也不同;若不注意线程隔离,多个任务共用同一个线程池,很可能会因为某个任务执行失败、线程池停止,导致别的任务也停止执行。
线程池工厂类如下:
/**
* Created by wanggenshen
* Date: on 2018/11/3 16:25.
* Description: 线程池工厂类
*/
public final class ThreadPoolFactory {
private static int CORE_POOL_SIZE = 5;
private static int MAX_POOL_SIZE = 10;
private static int KEEPALIVE_SECONDS = 120;
private static int QUEUE_SIZE = 120;
// 创建一个名为FILE_EXECUTOR的线程池,用于多线程读取文件字数
public static final ExecutorService FILE_EXECUTOR;
public ThreadPoolFactory() {
}
static {
// 线程池创建
FILE_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAX_POOL_SIZE,
(long)KEEPALIVE_SECONDS,
TimeUnit.SECONDS,
new ArrayBlockingQueue(QUEUE_SIZE),
new ThreadFactoryBuilder().setNameFormat("thread-pool-%d").build(),
new ThreadPoolFactory.MyRejectedExecutionHandler());
}
/**
* 自定义Reject策略
*/
static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
try {
executor.getQueue().put(