zoukankan      html  css  js  c++  java
  • ThreadPoolExecutor 几个疑惑与解答

    1. 任务是否都要先放入队列?
      当工作线程数小于核心线程数时,任务是不会经过队列,而是直接创建 Worker 时传入。但是如果工作线程数已经大于核心线程数,则任务是要先放入队列的。实际上只要是被创建的工作线程所执行都是不需要经过工作队列的,而是在创建新工作线程时作为参数传入处理。对应就是调用 addWorker 方法的地方。
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            // 工作线程数<核心线程数,创建核心线程并直接执行该任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 工作线程数大于核心线程数,小于最大允许线程数,创建线程并执行该任务
        else if (!addWorker(command, false))
            reject(command);
    }
    
    1. 什么时候创建额外的线程
      队列已经满了,并且当前工作线程数小于最大允许线程数才会创建额外的线程。实际上所有调用 addWorker 方法的地方都会经过该判断。
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 队列队列已经满了,才会执行 addWorker 逻辑
        else if (!addWorker(command, false))
            reject(command);
    }
    
    
    // addWorker 中的部分代码
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
    
        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
    
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 增加新的线程数
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get(); // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }
    
    1. 怎么销毁多余线程
      当队列中没有任务之后,执行的线程将会被销毁。
        final void runWorker(Worker w) {
            Thread wt = Thread.currentThread();
            Runnable task = w.firstTask;
            w.firstTask = null;
            w.unlock(); // allow interrupts
            boolean completedAbruptly = true;
            try {
                // getTask() 返回为null,也就是队列中没有任务了
                while (task != null || (task = getTask()) != null) {
                    // 省略代码
                }
                completedAbruptly = false;
            } finally {
                // 移除worker
                processWorkerExit(w, completedAbruptly);
            }
        }
    
    1. 如何实现让多余线程在指定时间后销毁?
      超过核心线程数的线程,获取队列任务会使用 poll 方法,增加阻塞时间,如果在指定的时间没有任务到达,就会返回null,从而销毁该线程
        private Runnable getTask() {
            boolean timedOut = false; // Did the last poll() time out?
    
            for (;;) {
                int c = ctl.get();
                int rs = runStateOf(c);
    
                // Check if queue empty only if necessary.
                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                    decrementWorkerCount();
                    return null;
                }
    
                int wc = workerCountOf(c);
    
                // Are workers subject to culling?
                boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    
                if ((wc > maximumPoolSize || (timed && timedOut))
                    && (wc > 1 || workQueue.isEmpty())) {
                    if (compareAndDecrementWorkerCount(c))
                        return null;
                    continue;
                }
    
                try {
                    // poll 方法设置时间,也就是获取任务增加阻塞时间
                    Runnable r = timed ?
                        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                        workQueue.take();
                    if (r != null)
                        return r;
                    timedOut = true;
                } catch (InterruptedException retry) {
                    timedOut = false;
                }
            }
        }
    
    1. Worker 继承AQS的作用
      继承了AQS类,可以方便的实现工作线程的中止操作;
    2. 可以设置的最大线程数
      2^29 次方,因为ctl高三位被用于表示当前线程池的状态了,所以只有29位用于表示最大线程池的大小。
        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;
    
    1. 拒绝策略什么时候起作用?
      工作线程数已经达到 maximumPoolSize,并且队列已经满了,则会启用拒绝策略
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            // 工作线程数<核心线程数,创建核心线程并直接执行该任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            // 工作线程数已经达到达到设置值,队列也已经满,则拒绝
            reject(command);
    }
    

    欢迎转载,但请注明本文链接,谢谢你。
    2019.04.21 17:47

  • 相关阅读:
    Activity 生命周期 返回键 退出 杂谈
    多线程基本语法
    常用代码
    JSP 相关
    powerDesiger uml class
    抽象类的说明
    javaScript 中常用的正则表达式
    chickbox 的使用
    对象在内存中的状态
    jQuery 常用代码
  • 原文地址:https://www.cnblogs.com/xiaoheike/p/10745999.html
Copyright © 2011-2022 走看看