java多线程(5)之线程池概念理解

来源:互联网 发布:职业经理人 知乎 编辑:程序博客网 时间:2024/06/01 08:54

Executor说明

Executor接口,是从JDK1.5开始就有的,里面只有一个接收参数为runnable的execute方法,若runnable为null,该方法回抛出NullPointerException,若这个任务无法被执行就会抛出RejectedExecutionException异常,execute方法可以在一个新线程,也可以在调用者线程中执行。
* @since 1.5public interface Executor {   void execute(Runnable command);}

ExecutorServices说明

ExecutorServices是一个扩展了Executor的接口,里面声明了任务的执行,任务结果的返回,任务的终止。
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;}

AbstractExecutorServices说明

AbstractExecutorServices抽象类实现了ExecutorServices接口,并对里面的一些方法做了初步的封装,下面的源码摘出了一部分,更多的内容可以在java.util.concurrent.AbstractExecutorServices中查看.
public abstract class AbstractExecutorService implements ExecutorService {    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {        return new FutureTask<T>(runnable, value);//封装成了FutureTask    }    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {        return new FutureTask<T>(callable);    }    public Future<?> submit(Runnable task) {        if (task == null) throw new NullPointerException();        RunnableFuture<Void> ftask = newTaskFor(task, null);//再次进行封装        execute(ftask);//调用execute才是真的执行任务        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;    }    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)        throws InterruptedException {        if (tasks == null)            throw new NullPointerException();        //创建ArrayList集合,用来保存要执行的任务。            ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());        try {            for (Callable<T> t : tasks) {                RunnableFuture<T> f = newTaskFor(t);//创建FutureTask任务                futures.add(f);//将FutureTask加入集合中                execute(f);//循环调用execute方法执行FutureTask任务            }            for (int i = 0, size = futures.size(); i < size; i++) {                Future<T> f = futures.get(i);                if (!f.isDone()) {                    try { f.get(); }//循环获取任务的执行结果,等所有任务执行结束返回携带任务结果的futures;                    catch (CancellationException ignore) {}                    catch (ExecutionException ignore) {}                }            }            return futures;        } catch (Throwable t) {            cancelAll(futures);//如果任务执行过程中出现异常就取消所有的任务执行并抛出异常结束            throw t;        }    }    private static <T> void cancelAll(ArrayList<Future<T>> futures) {        cancelAll(futures, 0);//中断后续所有的任务    }    /** Cancels all futures with index at least j. */    private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {        for (int size = futures.size(); j < size; j++)            futures.get(j).cancel(true);//中断任务的执行    }}

ThreadPoolExecutor说明

ThreadPoolExecutor继承AbstractExecutorService,线程池的具体实现类,一般用的各种线程池都是基于这个类实现的,提供了线程池的创建,提供了四个构造函数
public class ThreadPoolExecutor extends AbstractExecutorService {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,                              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;    }}
使用线程池的好处是:大大减少创建和调度线程的性能开销,在刚开始创建线程池的时候,默认情况下线程池中是没有任何线程的,只有等到新的任务时才会创建线程并执行。其中构造函数参数解释:
  1. corePoolSize:核心线程池的大小
  2. maximumPoolSize:线程池的最大容量
  3. keepAliveTime:空闲线程存活的时间
  4. unit:空闲线程存活时间的时间单位
  5. workQueue:线程池中的阻塞队列,用来存储等待执行的线程。
  6. threadFactory:创建线程的工厂
  7. handler:线程拒绝策略

线程池的流程图:(摘抄自ThreadPoolExecutor)
这里写图片描述

step1:主线程中调用ThreadPoolExecutor.execute方法,首先检查corePool中的线程数是否小于corePoolSize,如果是,就创建新线程放入corePool中并执行.

step2:如果不是,检查阻塞队列中是否已满,如果没有满,就将线程放入队列中。

step3:如果阻塞队列已经满了,检查线程池中的线程数是否超越maximumPoolSize,如果没有,就创建新的线程并执行。

step5:如果线程池中的数量超过了maximumPoolSize就执行handler拒绝策略.

#这里进一步解释下阻塞队列:BlockingQueue它是一个包含从队列中存取抽象方法的接口,我们在创建线程池的时候一般都是使用其自类实现,主要包括以下几个:
  • ArrayBlockingQueue(有边界的队列,内部是动态数组实现,一旦指定大小不可改变,采用FIFO方式处理)
  • LinkedBlockingQueue(阻塞队列大小的配置是可选的,如果我们初始化时指定一个大小,它就是有边界的,如果不指定,它就是无边界的。说是无边界,其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表)
  • SynchronousQueue: SynchronousQueue队列内部仅允许容纳一个元素。当一个线程插入一个元素后会被阻塞,除非这个元素被另一个线程消费。队列的详细说明请看【Java并发之】BlockingQueue
handler:拒绝处理任务的策略:
  • AbortPolicy:丢弃任务并抛出RejectExecutionException异常,这也是线程池中默认的方法.
  • DiscardPolicy:丢弃任务并且什么也不做.
  • DiscardOldestPolicy:丢弃队列最前面的任务,然后尝试执行execute.
  • CallerRunsPolicy:直接由调用线程执行。

线程池调用submit和execute方法的源码建议大家去看看,试着去理解里面的细节.


Executors类是辅助创建线程池的类,一共提供了四类八种类型,另外提供了获取线程工厂的实例和其他的处理callable的方法。

  1. newFixedThreadPool:创建指定线程长度的线程池, 超出的线程会放进队列中.
  2. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.
  3. newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
  4. newScheduledThreadPool:创建指定的线程长度的线程池,这个数量的线程池会一直存在即是它是空闲的。(内部实现是延时队列delayQueue).
原创粉丝点击