美文网首页
ThreadPoolExecutor

ThreadPoolExecutor

作者: 永远的太阳0123 | 来源:发表于2018-10-09 21:02 被阅读0次

    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.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:核心线程数。
    (2)int maximumPoolSize:最大线程数,线程池中允许创建的最大线程数。
    (3)long keepAliveTime:空闲线程的存活时间。如果某线程的空闲时间超过这个值,那么这个线程就可以关闭了。这个存活时间并不会对所有线程都起作用,如果线程池中的线程数小于等于corePoolSize,那么这些线程不会因为存活时间太长而关闭。当然,也可以调用allowCoreThreadTimeOut(true)使核心线程数内的线程也可以被回收。
    (4)TimeUnit unit:存活时间的单位。
    (5)BlockingQueue<Runnable> workQueue:任务队列,BlockingQueue接口的某个实现类对象(常使用ArrayBlockingQueue和LinkedBlockingQueue)。
    (6)ThreadFactory threadFactory:用于生成线程,一般使用默认的就可以。可以通过这个参数使线程名称更具可读性,例如Message-Thread-1,Message-Thread-2。
    (7)RejectedExecutionHandler handler:当线程池已满,又有新任务提交时,采取什么样的策略。有几种策略可供选择,例如抛出异常、直接拒绝并返回等,也可以自己实现相应的接口以实现自己的逻辑。

    然后我们再看看其它的重要属性。
    有一个32位的整数用于存放线程池的状态和线程数,其中高3位用于存放线程池状态,低29位用于存放线程数

    Doug Lea 采用一个 32 位的整数来存放线程池的状态和当前池中的线程数,其中高 3 位用于存放线程池状态,低 29 位表示线程数(即使只有 29 位,也已经不小了,大概 5 亿多,现在还没有哪个机器能起这么多线程的吧)。我们知道,java 语言在整数编码上是统一的,都是采用补码的形式,下面是简单的移位操作和布尔操作,都是挺简单的。

        // ctl的高3位代表线程池的状态,低29位代表线程池的线程数。
        // ctl初始值为11100000000000000000000000000000
        private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
        // 32-3=29
        private static final int COUNT_BITS = Integer.SIZE - 3;
        // 线程池最大容量为2^29-1=536870911,00011111111111111111111111111111
        private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
        // 11111111111111111111111111111111左移29位,得到11100000000000000000000000000000
        private static final int RUNNING    = -1 << COUNT_BITS;
        // 00000000000000000000000000000000
        private static final int SHUTDOWN   =  0 << COUNT_BITS;
        // 00100000000000000000000000000000
        private static final int STOP       =  1 << COUNT_BITS;
        // 01000000000000000000000000000000
        private static final int TIDYING    =  2 << COUNT_BITS;
        // 01100000000000000000000000000000
        private static final int TERMINATED =  3 << COUNT_BITS;
        // 将c的低29位设置为0。可以据此获得线程池的状态。
        private static int runStateOf(int c)     { return c & ~CAPACITY; }
        // 将c的高3位设置为0。可以据此获得线程池的线程数。
        private static int workerCountOf(int c)  { return c & CAPACITY; }
        private static int ctlOf(int rs, int wc) { return rs | wc; }
    
        private static boolean runStateLessThan(int c, int s) {
            return c < s;
        }
    
        private static boolean runStateAtLeast(int c, int s) {
            return c >= s;
        }
    
        private static boolean isRunning(int c) {
            return c < SHUTDOWN;
        }
    

    线程池的各种状态
    (1)RUNNING(-1):正常状态。也是线程池的初始状态。
    (2)SHUTDOWN(0):优雅关闭状态。不接受新的任务,但会继续处理等待队列中的任务(已添加的任务)。
    (3)STOP(1):不接受新的任务,不再处理等待队列中的任务(已添加的任务),尝试中断正在执行任务的线程。
    (4)TIDYING(2):所有已终止,workCount为0。线程池在转换到这个状态时,会执行terminate()方法。
    (5)TERMINATED(3):线程池彻底停止。terminated()方法执行完毕后线程池的状态。
    线程池的状态转换过程
    (1)RUNNING -> SHUTDOWN:调用shutdown()方法后,会发生这个状态转换。
    (2)(RUNNING/SHUTDOWN) -> STOP:调用shutdownNow()方法后,会发生这个状态转换。
    (3)SHUTDOWN -> TIDYING:当线程池和任务队列的任务执行完毕后,会发生这个状态转换。
    (4)STOP -> TIDYING:当线程池中执行的任务为空,会发生这个状态转换。
    (5)TIDYING -> TERMINATED:terminated()方法执行完毕后,会发生这个状态转换。

    相关文章

      网友评论

          本文标题:ThreadPoolExecutor

          本文链接:https://www.haomeiwen.com/subject/zlupoftx.html