ThreadPoolExecutor입니다 스레드 풀 "소스 코드 분석"

ThreadPoolExecutor입니다 스레드 풀 소스 코드 분석

하얀 치아는 말한다

긴 시간이 더 업데이트 배울하지 않을 이유지만, 완성 된 학교가 귀에서 소리의 파동뿐만 아니라, 작성하는 방법을 몰라 공개 번호, 공개보다는 사람들의 쓰기 수를 비행하는 것은, 동일한 주제를 대중 번호를 볼 수 있다고 나에게 말했다 기사 너무 많이 ....... 그러나 나중에 자신이 마무리 나는 유사한 글이 많이 있지만, 파악,하지만 난 그것을 기록하지 않았다는 우리가, 더 많이, 도움을 가져올 수 만 있다면, 관련 지식을 분류하는 데 도움이 하얀 치아, 이상의 출력을 장려 만 수확되는 출력 강제 입력은, 우리가 알아야 할

ThreadPoolExecutor입니다 类 图

ThreadPoolExecutor입니다 类 图

클래스 다이어그램 프로그램으로 ThreadPoolExecutor에가 ExecutorService를이 태스크는 스레드 풀에 의해 수행 될 수있다

공통 속성

// 线程池中重要的变量 ctl,类型为 AtomicInteger,一个变量同时记录线程池状态和线程个数
// Integer 的位数为 32 位,其中高 3 位表示线程池的状态,低 29 位表示线程的个数。默认为 RUNNING 状态,线程个数为 0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程个数掩码位数,去掉高 3 位代表线程个数的 bit 位
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程最大个数,低 29 位 00011111111111111111111111111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
复制代码

쓰기 JDK의 소스 코드는 국가의 동시 발현 다음과 같은 방법 일견와 관련된 스레드 풀 스레드의 수에 의해 이러한 족장, 잘 변수의 사용, CTL 가변 비트 작업에 감탄했다

일반적인 방법

// 计算线程池的状态 ~CAPACITY 为:11100000000000000000000000000000,通过让 ctl 与 ~CAPACITY 相与,相当于取高 3 位的值(前面说了 ctl 高 3 位表示线程池状态)
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 计算线程个数 CAPACITY 为:00011111111111111111111111111111,通过让 ctl 与 CAPACITY 相与,相当于取低 29 位的值(前面说了 ctl 低 29 位表示线程个数)
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 计算 ct l的值,用线程池状态和线程个数进行或运算
private static int ctlOf(int rs, int wc) { return rs | wc; }
复制代码

소스 코드에서 종종 우리는 이러한 방법은 매우 영리한 사용하지 않는 참조?

풀 라이프 사이클 스레드

// 默认状态,接收新任务并处理阻塞队列里的任务
private static final int RUNNING    = -1 << COUNT_BITS;
// 拒绝新任务但是处理阻塞队列里的任务
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 拒绝新任务并且抛弃阻塞队列里的任务,同时中断正在处理的任务
private static final int STOP       =  1 << COUNT_BITS;
// 所有任务都已经执行完成,线程数是 0,将调用 terminated() 方法
private static final int TIDYING    =  2 << COUNT_BITS;
// 终止状态,调用完 terminated() 方法后的状态
private static final int TERMINATED =  3 << COUNT_BITS;
复制代码

당신은 위의 변수 (I를 INT) Integer.toBinaryString 방법으로, 이진 표현이다보기를보고 싶다면

스레드 풀 변환의 주

RUNNING -> SHUTDOWN:当调用 shutdown() 方法时,也可能隐式的调用 finalize() 方法时(因为 finalize() 方法也是调用的 shutdown() 方法)
   On invocation of shutdown(), perhaps implicitly in finalize()
   
(RUNNING or SHUTDOWN) -> STOP:当调用 shutdownNow() 方法时
   On invocation of shutdownNow()
   
SHUTDOWN -> TIDYING:当队列和线程池都空时
   When both queue and pool are empty
   
STOP -> TIDYING:当线程池为空时
   When pool is empty
   
TIDYING -> TERMINATED:当 terminated() 方法完成时
   When the terminated() hook method has completed
复制代码

스레드 풀 생성자

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
复制代码

공통 파라미터와 같은 스레드 풀을 만들고, 다음과 같은 간단한 소개

corePoolSize:线程池中的核心线程数,即使他们处于空闲状态,除非 allowCoreThreadTimeOut 被设置了
maximumPoolSize:线程池中的最大线程数
workQueue:存放还未被执行任务的阻塞队列
threadFactory:创建线程的工厂类
rejectHandle:拒绝策略,当线程个数达到最大线程数,同时任务队列满了。就会执行拒绝策略。拒绝策略有:AbortPolicy(直接抛出异常)、CallerRunsPolicy(调用者所在线程来执行任务)、DiscardOldestPolicy(从任务队列中移除一个待执行的任务(最早提交的),然后再次执行任务)、DiscardPolicy(直接抛弃任务)      
keepAliveTime:存活时间,当线程个数大于了核心线程数,且处于空闲状态,这些空闲线程可存活的最大时间
复制代码

소스 해체

방법을 제출

() 스레드 풀을 사용하는 경우, 우리는 일반적으로 작업을 처리하기 위해 직접 스레드 풀에, ThreadPoolExecutor.submit (작업) 메소드를 호출하고 작업을 얻을 수있는 방법은하는 Future.get 결과 뒤에 다음, 우리에게 미래를 반환

public Future<?> submit(Runnable task) {
    // 任务为空,直接抛异常
    if (task == null) throw new NullPointerException();
    // 把任务封装成 RunnableFuture 
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    // 执行封装后的任务
    execute(ftask);
    return ftask;
}
复制代码
newTaskFor 방법

작업이 얻을 수있는 클래스의 RunnableFuture로 포장되어 newTaskFor 결과는 방법을 얻을

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

public FutureTask(Runnable runnable, V result) {
    // 这里把 Runnable 适配成 Callable 类型的任务,result 是当任务成功完成时返回的结果,如果需要特殊结  果,就用 null 就行了
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    // 这里通过 RunnableAdapter 适配任务和任务的结果
    return new RunnableAdapter<T>(task, result);
}

// 适配类 RunnableAdapter,这种写法,我们可以借鉴下
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}
复制代码
방법을 실행

새로운 될 수있는 작업을 수행하기 위해 스레드 풀 스레드에 작업을 실행하려고, 그것은 다중 스레드 풀 수 있습니다. 스레드 풀은 작업을 수행 할 수없는 경우 거부 정책을 실시한다 (두 가지 이유 1. 스레드 풀 2 스레드가 최대 용량에 도달 폐쇄되어있을 수 있습니다)

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:留着原汁原味的总结
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    
    // 获取表示线程池状态和线程个数的组合变量 ctl
    int c = ctl.get();
    // 判断线程个数是否小于核心线程数,如果小于就新建一个核心线程来执行任务
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
   // 如果线程池处于 RUNNAING 状态,就把任务添加到阻塞队列中(代码运行到这里说明要么线程个数>=核心线程数,要么执行 addWorder 方法失败)
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次获取组合变量 ctl,做二次检查(因为可能在此之前,线程池的状态已经发生了改变)
        int recheck = ctl.get();
        // 如果线程池状态不是 RNUUAING 状态,就把该任务从阻塞任务队列中移除,并执行拒绝策略
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 如果线程池中线程个数为 0,就新建一个线程
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 如果阻塞任务队列满了,新建线程,如果创建线程失败(即线程个数达到了最大线程个数),执行拒绝策略
    else if (!addWorker(command, false))
        reject(command);
}

复制代码
개요

작업이 실행되는 스레드의 수를 결정하는 스레드 풀에 제출 될 때 다른 스레드가 유휴 상태 인 경우에도이 작업을 처리하기 위해 적은 새로운 스레드가 아닌 경우, corePoolSize를보다 작습니다.

무료 커널 스레드, 직접 작업을 수행이 경우 다음, 작업을 온다. 핵심 스레드가 사용중인 경우, 수행 작업 큐에 추가하는 작업을했습니다.

작업 큐가 가득하고, 스레드의 수보다 적은 maximumPoolSize를보다 corePoolSize를 더 실행중인 경우에는 작업을 수행 할 수있는 새로운 스레드를 만들 것입니다.

addWorker 방법

첫 번째 (스레드 또는 스레드의 최대 개수의 코어 수)을 확인하기 위하여 여부 국경의 현재 상태와 스레드의 수에 따라 새 작업자 스레드 풀 스레드. 당신은 새로운 작업자 스레드 및 부팅 작업을 통해 다음 패스를 만들 수 있다면

/**
* 创建新的worker
*
* @param firstTask 提交给线程的任务,要最先执行,可以为 null
* @param core  如果为 true,表示以核心线程数为界创建线程  为 false 表示以最大线程数为界创建线程
* @return
*/
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        // 获取 ctl
        int c = ctl.get();
        // 获取线程池的状态
        int rs = runStateOf(c);

        // 这里的判断条件有点多,拆成 rs>=SHUTDOWN 和 !(rs == SHUTDOWN && firstTask == null &&!workQueue.isEmpty())
        // !(rs == SHUTDOWN && firstTask == null &&!workQueue.isEmpty()) 逆着考虑 ,如下:
        // rs!=SHUTDOWN 也就是为大于 shutdown,为 stop,tidying,terminated
        // firstTask != null
        // workQueue.isEmpty()
        // 如果线程池处于关闭状态,且满足下面条件之一的,不创建 worker
        //      线程池处于 stop,tidying,terminated 状态
        //      firstTask != null
        //      workQueue.isEmpty()
        // 注意:如果线程池处于 shutdown,且 firstTask 为 null,同时队列不为空,允许创建 worker
        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

        for (;;) {
            // 获取工作线程数
            int wc = workerCountOf(c);
            // 工作线程数大于最大容量或者工作线程数超过线程数的边界(根据 core 的值取不同的值) 时 不创建worker
            if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
            // 工作线程数 +1  通过 CAS
            // 这里如果失败,表示有并发操作
            if (compareAndIncrementWorkerCount(c))
                // 调出循环,执行真正的创建 worker 逻辑
                break retry;
            // 因为存在并发,需要再读取 ctl 值进行状态判断
            // Re-read ctl
            c = ctl.get();
            // 如果线程状态发生了变化,回到外部循环
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    // 校验已经都通过,开始创建 worker
    // 是否已经启动了 worker
    boolean workerStarted = false;
    // 是否已经添加了 worker
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 把 task 封装成 worker,通过线程工厂创建线程,最后会把任务设置到 Thread 的 target 属性上,后续在执行线程的 start 方法时,就会执行对应的任务的 run 方法
        w = new Worker(firstTask);
        // 获取 worker 中的线程
        final Thread t = w.thread;
        if (t != null) {
            // 获取对象锁
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                // 如果线程池处于 Running 状态 或者 线程池处于 shutdown 状态且任务为 null(执行任务队列中的任务)
                if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                    // precheck that t is startable
                    // 检查线程是否为启动状态,如果为启动状态抛异常
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    // 把新建的 worker 添加到 worker 集中
                    workers.add(w);
                    int s = workers.size();
                    // largestPoolSize 记录 workers 中个数存在过的最大值
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 新建的 worker 添加成功就启动线程,后续有分析
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 线程没有启动成功,对上面创建线程的过程做回滚操作
        if (! workerStarted)
            // 回滚操作,比如把 worker 从 workers 中移除,把线程数减一
            addWorkerFailed(w);
    }
    return workerStarted;
}

复制代码
addWorkerFailed 방법

롤백 작업자 스레드 생성하기 전에

private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
            // 从 workers 中移除 worker
            workers.remove(w);
        // 把线程数减一
        decrementWorkerCount();
        tryTerminate();
    } finally {
        mainLock.unlock();
    }
}

复制代码

addWorker 방법을 소개 woker 새로 성공적으로 스레드 woker 세트에 추가하여 만든 경우 논리 스레드가, 방법을 시작합니다 스레드가 호출 될 때, 사실, 마지막은 노동자의 실행 방법에 실행됩니다. thread 팩토리에 의해 Woker 생성자 스레드가 생성되기 때문에, 같은 다음 분석

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    // 这里默认的线程工厂是 DefaultThreadFactory
    this.thread = getThreadFactory().newThread(this);
}

复制代码

스레드, 마지막 호출 스레드의 생성자 스레드 (... Runnable를 대상 ...)에 의해 스레드 공장 만들기, 작업 후가 실행을 대상 매개 변수로 스레드를 생성 한 다음 실행 Thread.start 실행 방법 후 메소드를 호출하고 수행 할 target.run, 유사한 에이전트

@Override
public void run() {
    if (target != null) {
        // 这个 target 就是创建线程时传递过来的那个任务
        target.run();
    }
}

复制代码

그럼 당신은 우리의 근로자를 실행하는 방법을 실행할 수있는 실행 방법은 runWorker 메서드를 호출하여이 방법에서의 모습을 드릴 것입니다

runWorker 방법

작업 큐에서 작업을 계속하고 실행

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    // 把 status 设置为 0,允许中断
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 从任务队列中获取任务并执行
        while (task != null || (task = getTask()) != null) {
            // 这里加锁是为了避免任务运行期间,其他线程调用 shutdown 方法关闭线程池中正在执行任务的线程
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt

            // 如果线程池状态大于或等于 stop,即 runStateAtLeast(ctl.get(), STOP) 为 true,这个时候就要确保线程是中断的
            // 不用看||后面的条件,直接判断  !wt.isInterrupted(),因为线程池状态为暂停,要确保线程中断,如果没有中断,就要手动中断线程,即执行 wt.interrupt()
            // 如果线程池状态不是 stop,即 runStateAtLeast(ctl.get(), STOP) 为 false,就要确保线程没有中断,这样才能在后面执行任务
            // 这时候需要看 || 后面的 (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)) ,因为要确保线程没有中断,调用Thread.interrupted()清除中断状态,
            // 这里需要再次进行验证线程池的状态,因为可能会有 shutdownNow 的情况
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                // 空方法体,子类可以实现,做一些特殊化处理工作
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    // 执行任务
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    // 空方法体,子类可以实现,做一些特殊化处理工作
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                // 统计当前 worker 完成了多少任务
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        // 执行清理工作
        processWorkerExit(w, completedAbruptly);
    }
}

复制代码

runWorker 방법에서, 방법를 getTask, 다음과 같은 간단한있다

를 getTask 방법
private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 满足下面两种情况任意一个就返回 null 同时把线程个数减 1
        // 1.线程池已经处于关闭状态
        // 2.线程池处于 shutdown,且队列为空
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);
        // 判断线程是否有时效性,前面说过,如果把 allowCoreThreadTimeOut 设为 false,那么核心线程数以内的线程是不会关闭的。如果设为 true 就只会存活 keepAliveTime 这么长时间
        // 如果线程数大于核心线程数的线程都有时效性
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // 这个判断逻辑就是下面方法总结的第①点和第④点(这段代码我看了足足有半个小时,结合方法的注释终于弄明白了,感觉自己好笨)
        // 超时且超时的 worker 线程需要终止。
        // 如果任务队列非空,要保证当前 worker 线程不是线程池中最后一个线程(如果任务为空,当前线程是线程池中的最后一个线程也无妨,毕竟任务队列为空,当前 worker 线程关闭就关闭了,没影响)
        // 这里的判断条件可以看成 if (wc > maximumPoolSize || ((timed && timedOut) && (wc > 1 || workQueue.isEmpty()))
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // 从队列中取任务,分为有超时限制和非超时限制两种情况
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            // 这里会抛出中断异常是因为可能会调用 setMaximumPoolSize 方法,把线程的最大数设置小了,那可能存在当前线程数大于新的最大线程数
            // 这样就得关闭多余的线程,所以重新进入 for 循环,并返回 null
            timedOut = false;
        }
    }
}

复制代码
개요를 getTask 방법

작업 1. 반환

2. NULL을 반환,이 경우는 작업자 스레드의 요구 때문에 스레드의 수 감소,이 상황에 대해 다음 네 가지 이유로 그만이다

(a setMaximumPoolSize 방법에 의해 제공 될 수있는) ① 풀 스레드의 수는 스레드의 최대 수보다 크다

② 스레드 풀 폐쇄 [작업 모두가 새로운 작업을 거부하지 작업 대기열]

작업 큐가 비어있는 동안 ③ 스레드 풀은, 종료에 [] 새 작업을 거부

④ 초과 근무 및 종료 초과 근무 작업자 스레드. 작업 큐가 비어 있지 않은 경우, 현재의 thread가 마지막 스레드 작업자 스레드 풀 작업이 비어있는 경우, 현재의 thread가 마지막 스레드 풀 스레드가 결국, 작업 대기열이 비어, 어쨌든 (아니라는 것을 확인하기 위해, 현재 작업자 스레드가 닫히고 종료 )에 영향을 미치지 않았다

runWorker 정리 작업 processWorkerExit 방법을 수행하는 방법이있다, 다음과 같은 간단한 소개

processWorkerExit 방법
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 如果是突然完成,需要调整线程数
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();

    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 计算线程池完成的任务个数,并从 worke r线程集中删除当前 worker 线程
        completedTaskCount += w.completedTasks;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    // 尝试把线程池的状态设置为 TERMINATED,该方法在后面分析
    tryTerminate();

    int c = ctl.get();
    // 线程池状态至少为 STOP
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        // 新建 worker 线程的条件为:当前线程数小于核心线程数或者任务队列不为空但没有运行的线程了(允许核心线程超时的情况下)
        addWorker(null, false);
    }
}

复制代码
tryTerminate 방법
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        // 如果处于下面三种任意一种情况,就不能把线程池的状态设为 TERMINATED
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        // 代码执行到这里,说明有资格终止了。但是如果这个时候线程个数非 0,就中断一个空闲的线程来确保 shutdown 信号传播
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 设置线程池状态为 TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    // 设置线程池状态为 TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 激活调用线程池中因调用 awaitTermination 系列方法而阻塞的线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

复制代码

여기에이 문서의 소스와 함께주의 깊게 보면, 그것은 바로 스레드 풀의 구현 원리에 대한 약간의 느낌을해야 하는가? 남아있는 마지막 아래 내용은 스레드 풀 폐쇄 방법

종료 방법
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 权限校验
        checkShutdownAccess();
        // 设置线程池状态为 SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 中断空闲线程
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    // 尝试设置线程池状态为 TERMINATED
    tryTerminate();
}

复制代码
shutdownNow의 방법
public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 权限校验
        checkShutdownAccess();
        // 设置线程池状态为 STOP
        advanceRunState(STOP);
        // 中断所有线程
        interruptWorkers();
        // 将任务队列中的任务移动到 tasks 中
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    // 尝试设置线程池状态为 TERMINATED
    tryTerminate();
    return tasks;
}

复制代码

추신

이 문서는 지식의 스레드 풀의 작은 조각을 분류하는 방법으로 휴가를 기록, 물론, 어쩌면 문제, 하얀 치아가 문제가 대중 번호를 갈 수 있음이 상속을 비판 할 수 있기를 바랍니다 발견은 [일] 메시지가 매일 하얀 치아를 지적 또한 dingaiminIT, 우리는 교환을 논의 편지 [마이크로]을 추가 할 수 있습니다.

권장 역사 기사

클래스 로더 지식 구토 마무리

최종 표면 (5) 자격을 제공 명성 후 알리, 삼면, 다행히 자격 보간 장소에 걸려

원래 | ES 광고 역 색인 구조의 진화 및 최적화

광고 아키텍처와 최적화 된 역 색인

CPU 사용량이 너무 높고 너무 JVM 된 조사 과정을 점령

FGC는 ​​자주 살인자로 밝혀졌다

기존 100 % 년은 그런데 버그가 vertx - 레디 스 클라이언트의 발견, 점령

KafkaProducer 소스 코드 분석

네트워크 계층의 카프카 서버 소스 코드 분석

레디 스 만료 정책은 어떻게 달성하는 것입니다?

원래 | HashMap에이 두 점을 경우, 인터뷰는 아무 문제가 없습니다 이해

원래 | 면접관 : 자바 수행해야 힙에 할당 된 객체?

원래 |이 포장 질문은, 대부분의 사람들은 잘못있어

동료 :은 "재시도"추상적 밖으로는 같은 도구가 될 수 있습니다

참고 자료

  1. juejin.im/entry/59b23...
  2. "자바 비동기 실제 프로그래밍은"대중의 관심을 환영 [번호] 표백 치아 최신 기사 매일, 우리가 함께 의사 소통, 함께 진행!

추천

출처juejin.im/post/5e4602d66fb9a07c8a5a0d08