1、Executor线程池框架
JDK1.5引入了Executor线程池框架,通过它把任务的提交和执行进行解耦,我们只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。
java.util.concurrent.Executor: 大部分线程池相关的接口都是实现这个接口的
public interface Executor {
void execute(Runnable command);
}
该接口的继承实现有:
工作中常见到的是上面我圈起来的两个东西,当我们去看源码后,可以发现其实ThreadPoolExecutor也继承至ExecutorService(如下图所示)。顾名思义ExecutorService就是提供线程服务的接口。
2、初始化一个ExecutorService
ExecutorService defaultExecutorService = new ThreadPoolExecutor(corePoolSize,
maxPoolSize,
keepAliveTime,
timeUnit,
workQueue,
threadFactory,handle);
方法参数:
corePoolSize:核心线程数
maxPoolSize:最大线程数
keepAliveTime:线程存活时间(在corePore<*<maxPoolSize情况下有用)
timeUnit:存活时间的时间单位
workQueue:阻塞队列(用来保存等待被执行的任务)
注:关于workQueue参数的取值,JDK提供了4种阻塞队列类型供选择:
ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
inkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任;
SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直 处于阻塞状态,吞吐量通常要高于ArrayBlockingQuene;
PriorityBlockingQuene:具有优先级的无界阻塞队列;
threadFactory:线程工厂,主要用来创建线程;
handler:表示当拒绝处理任务时的策略,有以下四种取值
注: 当线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
3、4种类型的线程池
其实除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,timeUnit,workQueue,threadFactory,handle)实现的,只是参数不同而已。
1)newFixedThreadPool()
说明:初始化一个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene作为阻塞队列
特点:即使当线程池没有可执行任务时,也不会释放线程。
//构造源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2)newCachedThreadPool()
说明:初始化一个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
特点:在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源;当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;因此,使用时要注意控制并发的任务数,防止因创建大量的线程导致而降低性能。
//构造源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
3)newSingleThreadExecutor()
说明:初始化只有一个线程的线程池,内部使用LinkedBlockingQueue作为阻塞队列。
特点:如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行
//构造源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
4)newScheduledThreadPool()
特定:初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。
总结:除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。
//构造源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
4、给大家分享一个Executor工具类:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtil.class);
private static final int THREAD_SIZE = 20;
private static final int MAXIMUM_POOL_SIZE = 200;
private static final int WORKER_QUEUE_SIZE = 1024;
private static final int KEEP_ALIVE_TIME = 0;
private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("yf-pool-%d").build();
private static final ExecutorService defaultExecutorService = new ThreadPoolExecutor(
THREAD_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.MINUTES,
new LinkedBlockingQueue<>(WORKER_QUEUE_SIZE),
threadFactory, new ThreadPoolExecutor.AbortPolicy());
/**
* 使用默认线程池处理单个任务,不等待处理完成就返回
* @param task
*/
public static void execOneTaskWithNoWait(Runnable task)
{
execTaskListWithNoWait(defaultExecutorService,new ArrayList<Runnable>(){{add(task);}});
}
/**
* 使用业务特定线程池处理单个任务,不等待处理完成就返回
* @param task
*/
public static void execOneTaskWithNoWait(ExecutorService threadPool, Runnable task)
{
execTaskListWithNoWait(threadPool,new ArrayList<Runnable>(){{add(task);}});
}
/**
* 使用默认线程池处理任务,不等待处理完成就返回
* @param taskList
*/
public static void execTaskListWithNoWait(List<Runnable> taskList)
{
execTaskListWithNoWait(defaultExecutorService,taskList);
}
/**
* 使用业务特定线程池处理,不等待处理完成就返回
* @param threadPool
* @param taskList
*/
public static void execTaskListWithNoWait(ExecutorService threadPool, List<Runnable> taskList)
{
if(threadPool==null || CollectionUtils.isEmpty(taskList))
{
return;
}
for(Runnable task : taskList)
{
threadPool.execute(() -> doTask(task));
}
}
private static void doTask(Runnable task) {
try {
task.run();
} catch (Exception e) {
LOGGER.error("parallelExecWithNoWait run task error!",e);
}
}
}