线程池
在Java多线程中,如果并发的线程数量过大,并且每一个线程都是执行了一个很短的任务就结束了,这样频繁的创建销毁线程会极大的降低系统的效率。所以在Java中引入 了线程池使得线程可以得到复用。既执行完一个任务不会被销毁而去执行下一个任务。
以下基于jdk1.7.8.1源码来进行分析
目录
线程池的继承关系
Excutor接口:
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the <tt>Executor</tt> implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution.
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
它只有一个执行方法execute();
ExecutorService接口:
它提供了将任务交给执行者的方法(submit())、关闭(shutDown())...
AbstractExecutorService类:
一个抽象类主要是实现了ExecutorService接口的方法。
ThreadPoolExecutor类 :
实现线程池最主要的类。
线程池的基本属性
//线程池的状态
volatile int runState;
static final int RUNNING = 0;//运行状态
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
private final BlockingQueue<Runnable> workQueue;//缓存队列
//互斥锁
private final ReentrantLock mainLock = new ReentrantLock();
//终止条件
private final Condition termination = mainLock.newCondition();
//存放线程的工作集
private final HashSet<Worker> workers = new HashSet<Worker>();
private volatile long keepAliveTime;//空闲时间
//表示是否允许线程在空闲状态仍能存活
private volatile boolean allowCoreThreadTimeOut;
private volatile int corePoolSize;//核心池大小
private volatile int maximumPoolSize;//最大池大小
private volatile int poolSize;//当前大小
/**
*表示当拒绝处理任务时的策略,有以下四种取值
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
*/
private volatile RejectedExecutionHandler handler;
private volatile ThreadFactory threadFactory;//线程工厂
private int largestPoolSize;//记录之前线程最大时的大小
private long completedTaskCount;
corePoolSize:核心池的大小。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达 的任务放到缓存队列中。
maximumPoolSize:线程池最大线程数。表示在线程池中最多能创建多少个线程。
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程数大于corePoolSize时,keepAliveTime 才会起作用,直到线程池中的线程数不大于corePoolSize。,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时 间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut()方 法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
WorkQueue:阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,要对线程池的运行过程产生重大影响。
- ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小。
- LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_Vlaue
- SynchronousQueue:这个队列比较特殊,它不会保存提交的任务 ,而是直接创建了一个线程去执行新来的任务
threadFactory:线程工厂,用来创建线程
Hander:表示当拒绝处理任务时的策略,有以下四种取值
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an <tt>AbortPolicy</tt>.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always.
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//抛出异常
throw new RejectedExecutionException();
}
}
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a <tt>DiscardPolicy</tt>.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a <tt>DiscardOldestPolicy</tt> for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a <tt>CallerRunsPolicy</tt>.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
线程池的构造函数
构造函数——1
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
第一个构造函数,调用了最后一个构造函数。它调用了默认的线程工厂和默认的拒绝策略
static class DefaultThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null)? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//设置线程名字
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
//创建一个线程
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
//设置为非守护线程
if (t.isDaemon())
t.setDaemon(false);
//设置线程优先级
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
这是默认的线程工厂,里面设置了线程的名字,设置线程为非守护线程,设置优先级为Thread.NORM_PRIORITY
构造函数——2
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
调用了最后一个构造函数。它使用了默认的拒绝策略
构造函数——3
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
调用了最后一个构造函数。它使用了默认的线程工厂
构造函数——4
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;
}
最终实现的构造函数,进行了对参数的检测处理。如果核心池大小小于0或者最大池大小小于等于0或者核心池大小大于最大池大小或者空闲等待时间小于0 就抛出IllegalArgumentException异常。如果阻塞队列为null或者线程工厂为null或者拒绝策略为null就抛出NullPointerException异常。
线程池的执行流程
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
线程池的终止
Shutdown()和shutdownNow()两个方法,用于线程池的关闭。
Shutdown():不会立即终止线程池,而是要等待所有的任务缓存队列中的任务都执行完才终止,但也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
public void shutdown() {
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (security != null) { // Check if caller can modify our threads
for (Worker w : workers)
security.checkAccess(w.thread);
}
int state = runState;
//线程状态改变
if (state < SHUTDOWN)
runState = SHUTDOWN;
try {
for (Worker w : workers) {
w.interruptIfIdle();//终止任务
}
} catch (SecurityException se) { // Try to back out
runState = state;
// tryTerminate() here would be a no-op
throw se;
}
//尝试终止线程池
tryTerminate(); // Terminate now if pool and queue empty
} finally {
mainLock.unlock();
}
}
public List<Runnable> shutdownNow() {
/*
* shutdownNow differs from shutdown only in that
* 1. runState is set to STOP,
* 2. all worker threads are interrupted, not just the idle ones, and
* 3. the queue is drained and returned.
*/
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (security != null) { // Check if caller can modify our threads
for (Worker w : workers)
security.checkAccess(w.thread);
}
int state = runState;
if (state < STOP)
runState = STOP;
try {
for (Worker w : workers) {
//终止任务
w.interruptNow();
}
} catch (SecurityException se) { // Try to back out
runState = state;
// tryTerminate() here would be a no-op
throw se;
}
List<Runnable> tasks = drainQueue();
//尝试终止线程池
tryTerminate(); // Terminate now if pool and queue empty
return tasks;
} finally {
mainLock.unlock();
}
}
private void tryTerminate() {
if (poolSize == 0) {
int state = runState;
if (state < STOP && !workQueue.isEmpty()) {
state = RUNNING; // disable termination check below
addThread(null);
}
if (state == STOP || state == SHUTDOWN) {
//将线程状态设为TERMINATED
runState = TERMINATED;
//发送信号关闭线程池
termination.signalAll();
terminated();
}
}
}
Submit方法与Collable、Future
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Object> ftask = newTaskFor(task, null);
//调用了execute()方法
execute(ftask);
return ftask;
//返回一个Future对象
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
Callable也是实现多线程的一种办法。
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
它的call方法相当于Runnable的run方法。但是不同的是call方法可以抛出异常。Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)。运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它可以返回正在执行的任务,可以终止任务。