Java线程池

来源:互联网 发布:城市天际线mod软件 编辑:程序博客网 时间:2024/06/10 02:52


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<?>类型。

@FunctionalInterfacepublic 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来创建线程池。



0 0