Java的线程池存在于java.util.concurrent包中的Executor框架。Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。他们的关系为
图片来自第七城市网。
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 {@code Executor} 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);
}
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Excutors为真正的实现者。Executor作为顶级接口,ExecutorService接口继承了Executor接口,也是线程池ThreadExecutorPool线程池实现的接口。
建造线程池的方法有五种,分别建造不同的线程池:
newCachedThreadPool
newFixedThreadPool
newSingleThreadExecutor
newScheduledThreadPool
newSingleThreadScheduledExecutor
五种方法都会建造一个线程池,我们取其中一个解读一下:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可见,调用该方法最终返回了一个新建的ThreadPoolExecutor类型对象,也就是我们说的线程池。
继续追踪:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
ThreadPoolExecutor的构造函数,第一个参数是corePoolSize,核心线程数,核心线程在线程池中永远活跃。第二个参数maximunPoolSize,最大线程数,线程池可以运行的最大的线程数量。第三个参数keepAliveTime,非核心线程保持存活的时间。第四个参数unit,时间的单位。第五个参数workQueue,阻塞队列。
线程池中的核心线程始终保持活跃,当有任务来时,如果有核心线程空闲,立刻让其执行任务;如果没有核心线程空闲,即将任务加入工作队列。如果工作队列已满,又有任务过来了,那么开启一个新线程,执行任务,此时工作队列一直保持满的状态。开启的非核心线程执行任务结束后,如果在存活时间内没有接到任务,就会被关闭。当开启的线程数目达到最大线程数目,阻塞队列也已经排满,将会调用第七个参数defaultHandler,实行拒绝策略。
可见,上文的构造函数实际上调用了另一构造函数完成了构造。下面来看一看ThreadPoolExecutor的第一构造函数:
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;
}
由上可见,原生构造函数实际上有七个参数,除了上面提到的五个,还有ThreadFactory类型参数和RejectedExecutionHandler类型参数。第七个参数RejectedExecutionHandler上文也提到过了,它是线程池在线程达到最大线程数,且阻塞队列也达到满的状态时,调用的拒绝策略。
RejectedExecutionHandler:
public interface RejectedExecutionHandler {
/**
* Method that may be invoked by a {@link ThreadPoolExecutor} when
* {@link ThreadPoolExecutor#execute execute} cannot accept a
* task. This may occur when no more threads or queue slots are
* available because their bounds would be exceeded, or upon
* shutdown of the Executor.
*
* <p>In the absence of other alternatives, the method may throw
* an unchecked {@link RejectedExecutionException}, which will be
* propagated to the caller of {@code execute}.
*
* @param r the runnable task requested to be executed
* @param executor the executor attempting to execute this task
* @throws RejectedExecutionException if there is no remedy
*/
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
ThreadFactory:
public interface ThreadFactory {
/**
* Constructs a new {@code Thread}. Implementations may also initialize
* priority, name, daemon status, {@code ThreadGroup}, etc.
*
* @param r a runnable to be executed by new thread instance
* @return constructed thread, or {@code null} if the request to
* create a thread is rejected
*/
Thread newThread(Runnable r);
}
很明显,它是用来创建线程的。
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
这是newCachedThreadPool函数另一个重载形式。我们也可以调用这种构造函数指定ThreadFactory,设置线程池中的线程属性。
线程提交到线程池,需要调用ExecutorService接口中的submit函数:
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
线程池的submit函数有三种重载形式。三种形式的函数的返回值也不完全相同。
第一种,参数为Callable<T>类型,返回值为<T> Future<T>类型,均为可变参数。
第二种,参数为Runnable类型和T类型,返回值为<T> Future<T>类型。
第三种,参数为Runnable类型,返回值为Future<?>类型。
@FunctionalInterface
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;
}
Callable和Runnable类似,Callable<T>接口中仅有一个call方法,Runnable接口中仅有一个run方法,它们都是开启的新线程运行的函数体。不过Callable<T>的cal方法是有返回值的,返回值的类型也为T。
返回值的类型为Future<T>:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Future<T>中有多种方法,给使用者用来控制提交的任务的运行。cancel方法用来取消任务,参数用来确定是否允许在线程运行时进行中断。isCancelled方法用来查看任务是否被取消。isDone方法用来查看任务是否已经完成。get方法接收任务运行结束后的返回结果,这是一个阻塞操作。第二个get方法设置了阻塞的时长和时间单位。
由于Runnable的run方法没有返回值,所以,在submit中把Runnable作为参数还想要返回值的话,需要自己设定一个T类型的result参数,任务运行结束后,将返回result的值作为结果。
我们使用Executors创建的线程池,其最大线程都为Integer.MAX_VALUE,所以为了安全起见,我们一般直接使用ThreadPoolExecutor来创建线程池。