Java之线程池

2018-08-16  本文已影响23人  吴世浩

一、浩言

努力、努力、努力!!!

二、内容

2.1)、固定参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);

对于任务队列可以分为以下几种

2.2)、相关线程说明

2.2.1)、固定线程数-newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);

newFixedThreadPool使用了固定数量达线程数,队列使用了无界的LinkedBlockingQueue队列,因此,线程数据不存在变化,在到达固定线程后,新来的线程都放入队列,如果新加入的线程很多,则会一直加入队列,直到系统资源耗尽。

2.2.2)、单列线程池-newSingleThreadScheduledExecutor

 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

newSingleThreadExecutor和newFixedThreadPool差不多,只是newSingleThreadExecutor固定一个线程。

2.2.3)、可缓存线程-newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

newCachedThreadPool中的corePoolSize为0,而maximumPoolSize无穷达的线程池,这说明在没有任务的时候线程池中的线程数为0;当有任务提交的时候,该线程池会使用空闲的线程执行任务。若无空闲线程,则将任务加入到SynchronousQueue,SynchronousQueue是一种提交队列,当入队一个线程后会阻塞,一直等到被take后,才会存放下一个线程,因此,它总是会迫使线程池中增加新的线程执行任务。当任务执行完毕后,空闲的线程会在指定的时间内被回收。当有很多大量线程被提交,任务执行不够快时,会开启等量的线程,这样会耗尽系统的资源。

2.3)、拒绝策略

三、线程池ThreadPoolExecutor状态

源码中的注释解释如下:

RUNNING:  Accept new tasks and process queued tasks
运行中:接收新的任务并且处理已经入队的任务

SHUTDOWN: Don't accept new tasks, but process queued tasks
关闭:不接收新的任务,但是处理已经入队的任务

STOP:  Don't accept new tasks, don't process queued tasks,and interrupt in-progress tasks
停止:不接收新的任务,不处理已经入队的任务,并且中断进行中的任务

TIDYING:  All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the 
                  terminated() hook method
整理:所有任务已经执行完成,workerCount大小是0,线程状态切到TIDYING ,将会运行 terminated() 回调方法



TERMINATED: terminated() has completed
完成,terminated() 执行完成

源码

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }

其中ctl属性是控制状态,它有两层概念:

workerCount, indicating the effective number of threads
runState,    indicating whether running, shutting down etc

workCount:有效的线程数量
runState:当前线程池的状态

ctl中有29位来表示workerCount,3位来表示当前线程池的状态。

对于这里的位运算我还是没弄清楚,我自己尝试打印了下相关变量数据,但是觉得并没有什么用,具体计算还是位运算。

四、问答

1)问:当线程数达到coreSize后,没有请求后,coreSize个线程会被回收么?怎么回收coreSize的线程

首先,不会回收coreSize的线程;keepAliveTime是针对coreSize < n < maximumPoolSize的线程,空闲超过这个时间就会被回收超过coreSize的线程数量;

如果想要回收coreSize的线程数量,可以设置ThreadPoolExecutor属性allowCoreThreadTimeOut,源码中如下:

/**
     * If false (default), core threads stay alive even when idle.
     * If true, core threads use keepAliveTime to time out waiting
     * for work.
     */
    private volatile boolean allowCoreThreadTimeOut;
上一篇 下一篇

猜你喜欢

热点阅读