学习了Thread源码后,接下来学习一下线程池,在看源码前,先看一下该组件的几个接口、抽象类和实现类的结构关系。
Executor接口
ThreadPoolExecutor实现的顶层接口,顶层接口提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程和如何调度线程执行任务,用户只需要提供Runnable对象,将任务执行逻辑提交到执行器中,由Executor框架完成线程的调配和任务的执行部分。
public interface Executor {
void execute(Runnable command);
}
ExecutorService接口
扩充一个或一批异步任务生成Future的submit()方法。提供了shutdown()关闭线程池方法。
public interface ExecutorService extends Executor {
void shutdown();
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
}
AbstractExecutorService接口
将任务执行流程串起来,实现层只需要关注一个执行任务的方法。使用了“模板方法模式”,其它线程池想实现这些方法只需要实现Executor.execute()方法就可以了。
/**
* 该类主要实现了 ExecutorService 中的 submit()方法
*/
public abstract class AbstractExecutorService implements ExecutorService {
/**
* 提交任务,执行任务,返回获取未来结果的 Future对象。
* 模板方法模式
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
R unnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
}
ThreadPoolExecutor
学习ThreadPoolExecutor源码前,贴一个ThreadPoolExecutor的使用示例代码。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo {
private static final int CORE_POOL_SIZE = 5;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
private static final Long KEEP_ALIVE_TIME = 1L;
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 10; i++) {
Runnable worker = new MyRunnable("thread-" + i);
executor.execute(worker);
}
//关闭线程池
executor.shutdown();
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name){
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ">>" + name);
}
}
日志输出
pool-1-thread-1>>thread-0
pool-1-thread-4>>thread-3
pool-1-thread-3>>thread-2
pool-1-thread-2>>thread-1
pool-1-thread-4>>thread-7
pool-1-thread-2>>thread-8
pool-1-thread-3>>thread-6
pool-1-thread-1>>thread-5
pool-1-thread-4>>thread-9
pool-1-thread-5>>thread-4
进入主题>>>>
下面主要看一下ThreadPoolExecutor的主要代码部分。
主要属性
说起线程池,随口而出的便是它的主要属性:核心线程数、最大线程数、空闲时间、阻塞队列、拒绝策略。
//阻塞队列
private final BlockingQueue<Runnable> workQueue;
//创建线程工厂
private volatile ThreadFactory threadFactory;
//核心线程数
private volatile int corePoolSize;
//最大线程数
private volatile int maximumPoolSize;
//线程池维护线程所允许的空闲时间
private volatile long keepAliveTime;
//拒绝策略
private volatile RejectedExecutionHandler handler;
构造方法
//最后都使用了最后一个构造方法的实现
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
拒绝策略
/**
* 线程池对拒绝任务的处理策略,4种策略
*/
private volatile RejectedExecutionHandler handler;
//默认拒绝策略
private static final RejectedExecutionHandler defaultHandler =
new java.util.concurrent.ThreadPoolExecutor.AbortPolicy();
//1.AbortPolicy:默认策略,丢弃任务并抛出RejectedExecutionException异常。
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
//2.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
//3.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
//4.DiscardPolicy:丢弃任务,但不抛出异常。
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
主要实现
/**
* 执行线程任务
* @param command
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* 分三步进行:
* 1、如果运行的线程小于核心线程数,尝试开启一个新的线程;否则尝试进入工作队列。
* 2、如果工作队列没满,则进入工作队列;否则判断是否超出最大线程数
* 3、如果未超出最大线程数,则尝试开启一个新的线程;否则按饱和策略处理无法执行的任务
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
/**
* 在此过程中执行以前提交的任务,但不会接受新任务。如果调用已关闭,则不会产生额外的影响。
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
ThreadPoolExecutor 中的 execute()方法执行Runnable任务的流程逻辑可以用下图表示。
Executors工具类
在上面写了一个ThreadPoolExecutor使用的demo,下面简单介绍一下Executors线程池工具类。
它主要的作用就是提供一些static 的工具方法,为开发者提供各种封装好的具有各自特性的线程池,方便开发者创建线程池。
public class Executors {
/**
* 创建一个核心线程数和最大线程数相等的线程池
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* 创建一个单线程的线程池
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
/**
* 创建可动态伸缩的线程池。
* 核心线程数为0,最大线程数为Integer.MAX_VALUE,如果任务数在某一瞬间暴涨,存在一定的风险。
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
}
贴一个Executors的示例代码。
public class ExecutorsDemo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
Runnable worker = new MyRunnable("thread-" + i);
threadPool.execute(worker);
}
//关闭线程池
threadPool.shutdown();
}
}
日志输出
pool-1-thread-1>>thread-0
pool-1-thread-2>>thread-1
pool-1-thread-3>>thread-2
pool-1-thread-1>>thread-3
pool-1-thread-3>>thread-4
pool-1-thread-1>>thread-6
pool-1-thread-2>>thread-5
pool-1-thread-1>>thread-8
pool-1-thread-3>>thread-7
pool-1-thread-2>>thread-9
在日常的微服务开发的时候,大多都已习惯在spring环境下开发,经常用到的线程池便是ThreadPoolTaskExecutor,它和ThreadPoolExecutor有啥区别呢?
1、ThreadPoolTaskExecutor中使用了ThreadPoolExecutor,并对其进行了增强,扩展了更多的自有特性。 2、ThreadPoolTaskExecutor只关注自己扩展的那一部分特性,任务的执行还是由ThreadPoolExecutor来处理。 3、ThreadPoolTaskExecutor针对spring用起来更友好,离开spring我们用ThreadPoolExecutor。