深入学习java并发之线程池

这篇文章将从以下几个方面讲述Excutor框架以及线程池:

    。。。。

 

一、首先来看一下Executor框架的基本组成:

      

       1. Executor是一个基础的接口,设计它的目的就是将任务的提交与任务的执行解耦,所以这个接口里就只定义了一个方法:excute(Runaable command);

    源码:

 1 public interface Executor {
 2         //任务
 3      /* @param command the runnable task
 4         //几种饱和策略中,有一种饱和策略会抛出RejectedExecutionException
 5      * @throws RejectedExecutionException if this task cannot be
 6      * accepted for execution
 7         //如果任务为null会抛出NullPointerException
 8      * @throws NullPointerException if command is null
 9      */
10     void execute(Runnable command);
11 }    

  2.ExcutorService:不仅提供了列如shutdown的这种service的管理功能,也提供了能返回Future的的任务提交机制,而在其父接口Excutor中的提交方法不返回任何东西。

public interface ExecutorService extends Executor {
    //启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
    void shutdown();
    
    boolean isTerminated();
    //能返回Future而不是void的提交任务方法
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);   
    Future<?> submit(Runnable task);
    .......
    .......
    .......
}

  3.ThreadPolExecutor、ScheduledThreadPoolExecutor、ForkJoinPool则是Java标准类库为我们提供的几种基础实现。

  4.Excutors则是从简化使用的角度,为我们提供了各种静态工厂方法方便我们直接调用;

  

以下的文章以ThreadPoolExecutor讲解:

二、线程池 

  1、首先来看下ThreadPoolExecutor的构造函数有以下几种,我们以最下面的那个构造函数为例讲解,其他的构造函数内部都是通过调用最下面那个参数最多的构造函数来创建线程池的。

public ThreadPoolExecutor(    int corePoolSize,//核心线程数
                              int maximumPoolSize,//最大线程数
                              long keepAliveTime,//线程存活时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务阻塞队列
                              ThreadFactory threadFactory,//线程工厂
                              RejectedExecutionHandler handler//饱和策略(拒绝策略)
                                      ) {
        //如果核心线程数量小于0,或者最大线程数量小于等于0,或者最大线程数量比核心线程数量小,或者存活 
        //时间小于0,会抛出IllegalArgumentException。
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        //工作队列、线程工厂、饱和策略都不能为空,否则有一个为空就会报NullPointerException
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        
        //属性赋值
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }        

   从上面的源代码可以看出构造线程池需要以下几个参数:

    (1)int corePoolSize:核心线程数量 。 即使没有任务需要处理,核心线程也默认会一直存活。但是设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭

    (2)int maximumPoolSize 最大线程数量。线程池所能创建线程数量的上限。当核心线程全部都在处理任务时,如果此时来了新任务就会创建新的线程来处理新任务,但是线程池中总的线程数不能超过最大线程数量。

    (3)long keepAliveTime,//线程存活时间。线程数>maximumPoolSize时,空闲线程空闲时间达到线程存活时间时线程退出,直到线程数=核心线程数。

    (4)TimeUnit unit,//时间单位

         (5)BlockingQueue<Runnable> workQueue,//任务阻塞队列。新来的任务放到队列中,线程从队列中那任务执行

    (6)ThreadFactory threadFactory,//线程工厂

    (7)RejectedExecutionHandler handler//饱和策略(拒绝策略)。 在我们使用的队列是有界队列时,如果任务产生速度比线程池中线程执行任务的速度快得多,那么这个有界队列迟早会被填满。当有界队列被填满时,我们再想往队列中添加任务就无法添加了,这个时候饱和策略就会要发挥它的作用了。

      饱和策略可以分为三种:1)中止策略(抛异常)(默认使用它):这个策略会抛出RejectedExecutionException给他的调用者。

                                                             2)抛弃策略(抛任务):抛弃新来的这个任务。

                                                             3)抛弃最旧策略(抛任务):抛弃最旧的任务,也就是下一个将要执行的任务。(这个策略不要和优先队列一起使用)

                                                             4)调用者运行策略:返回给调用者让调用者运行。这个策略既不会抛出异常也不会抛弃任务,而是把任务退回给调用者让调用者执行,从而降低新任务的流量,具有一定的调节性。

 

     2、Excutors提供的的线程池。

    Excutors提供的的线程池都是通过它提供的静态方法来构建的,常用的主要为以下几种:

    1)newFixedThreadPool(int nThreads):线程数量固定,使用的工作队列为LinkedBlockingQueue

1 public static ExecutorService newFixedThreadPool(int nThreads) {
2         return new ThreadPoolExecutor(nThreads, nThreads,//核心线程和最大线程数量 
3                                                         //相等
4                                       0L, TimeUnit.MILLISECONDS,
5                                       new LinkedBlockingQueue<Runnable>());
6     }

 

              2)newSingleThreadExecutor()

1 public static ExecutorService newSingleThreadExecutor() {
2         return new FinalizableDelegatedExecutorService
3             (new ThreadPoolExecutor(1, 1, //核心和最大线程数量都为1,所以线程池只有一个线程
4                                     0L, TimeUnit.MILLISECONDS,
5                                     new LinkedBlockingQueue<Runnable>()));
6     }

 

      3)newCachedThreadPool()

              4)newScheduledThreadPool(int corePoolSize)

              5)newSingleThreadScheduledExecutor()

    6)newWorkStealingPool(int parallelism)


      

 

posted on 2018-09-13 14:49  ming_jia  阅读(283)  评论(1)    收藏  举报

导航