java 线程池 ThreadPoolExecutor 核心代码 原理浅析 jdk 1.8

一、前言

前段时间在公司分享过两次java线程池的实现原理,但是貌似大家理解的不是很深入,在应用的时候发现被培训的人并没有抓住核心点,并不理解线程池的核心原理,所以再完整的梳理一遍源码,希望可以帮助大家理解线程池的核心逻辑。本篇着重讲解ThreadPoolExecutor的使用及其核心代码,关于Executors的使用请参考我的另一篇博客https://blog.csdn.net/leandzgc/article/details/103082437

二、线程池的使用

2.1、构造函数源码

// 省略注释...
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
// 省略注释...
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
// 省略注释...
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
// 省略注释...
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;
    }

2.2、参数解析

核心线程数:int corePoolSize

不可小于0,初始创建的线程都是核心线程,线程池中正常情况下始终保留该大小的线程实例存活,哪怕没有任务空转也不会销毁该部分线程实例。

最大线程数:int maximumPoolSize

不可小于等于0,不可小于核心线程数,与核心数相等时没什么特殊作用。若大于核心数,且所有核心线程都处于繁忙状态,队列也已放满,新的任务提交时会创建新线程执行新任务(线程池内的工作线程实际上并未标记是否核心线程,只是逻辑上的核心线程及非核心线程,创建和销毁的最底层逻辑没区别)。线程池中实例化的最大线程对象数不会超过该参数值,若非核心线程处于空闲时间(当前任务执行完毕,不局限于第一次任务,若第一次刚执行完,来了新任务,非核心线程也会被复用的),且超过keepAliveTime配置的时间,则会销毁该非核心线程。

存活时间:long keepAliveTime

不可小于0,用于控制非核心线程数的空闲时存活时间(corePoolSize和maximumPoolSize一致时该参数配置了也没啥用)

存活时间的时间单位:TimeUnit unit

keepAliveTime参数对应的时间单位,可以是纳秒(TimeUnit.NANOSECONDS)、微秒(TimeUnit.MICROSECONDS)、毫秒(TimeUnit.MILLISECONDS)、秒(TimeUnit.SECONDS)、分钟(TimeUnit.MINUTES)、小时(TimeUnit.HOURS)、天(TimeUnit.DAYS)之间的一个。

线程池使用的阻塞队列:BlockingQueue<Runnable> workQueue

不可为空,当线程池中核心线程都处于繁忙状态,且有新的任务来临时,会把新的任务放入阻塞队列。阻塞队列放满后会尝试创建非核心线程,并使用非核心线程执行新任务。

线程池创建线程实例时使用的线程工厂:ThreadFactory threadFactory

不可为空,创建线程时使用该工厂构建线程池中的线程实例,不需要特殊处理可以给Executors.defaultThreadFactory(),使用自带的默认工厂。

线程池拒绝策略:RejectedExecutionHandler handler

不可为空,当核心线程数已耗尽且全部繁忙,队列已满,非核心线程数已耗尽且全部繁忙,会触发传入的拒绝策略。默认为AbortPolicy,直接抛出异常。自带了AbortPolicy、DiscardPolicy、DiscardOldestPolicy、CallerRunsPolicy四种,也可以自行实现RejectedExecutionHandler接口来处理。

2.3、使用示例

提交任务到线程池有以下几种方法
调用execute:仅能传递Runnable的实现类,也就是不带返回值(ThreadPoolExecutor中实现了祖宗接口Executor中的方法,在父类AbstractExecutorService的submit方法中会触发,也可以直接调用)

ThreadPoolExecutor tpe = new ThreadPoolExecutor(N_NUM_10, N_NUM_30, 0, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(N_NUM_10));
		tpe.execute(new Runnable() {
			public void run() {
				// 具体业务逻辑实现
			}
		});

方法声明

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
  // 省略核心代码...
}

调用submit:父类AbstractExecutorService提供的方法,返回Future<?>接口的实现类,可直接实例化比较常用的FutureTask<V>

// 创建一个future列表,用于接收线程执行结果
		List<Future<Boolean>> futureList = new ArrayList<Future<Boolean>>(N_NUM_10);
		// 创建线程池
		ThreadPoolExecutor tpe = new ThreadPoolExecutor(N_NUM_10, N_NUM_30, 0, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(N_NUM_10));
		// 提交线程任务
		for (int i = 0; i <= N_NUM_10; i++) {
			final Integer currNum = i;
			Future<Boolean> future = tpe.submit(new Callable<Boolean>() {
				public Boolean call() throws Exception {
					// 具体业务逻辑实现
					return currNum % N_NUM_2 == 0;
				}

			});
			futureList.add(future);
		}
		int oddNum = 0;
		int evenNum = 0;
		// 等待线程执行完毕,并获取线程执行结果
		for (Future<Boolean> future: futureList) {
			try {
				// 线程未执行完毕会阻塞
				if (future.get()) {
					evenNum ++;
				} else {
					oddNum ++;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("奇数共:" + oddNum + "个,偶数共:" + evenNum + "个");
		tpe.shutdown();

方法声明(有三种方法提交,根据自己的实际需要提交即可,比较常用的是第三个)

public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

三、核心代码解析

3.1、线程实例实例化及复用

任务入池主入口

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.
         * 
         * 1.如果正在运行的线程数少于corePoolSize,则尝试启动一个新的线程实例来运行给定的命令,
         * addWorker方法里面会自动校验runState和workerCount的正确性,在不成功的时候会返回false(返回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.
         * 
         * 2.如果加入队列成功(核心数已满,且均繁忙),系统还是会再次二次校验是否需要添加该线程(可能存在上次校验后线程池已终止的情况),
         * 	或者调用这个方法后线程被终止。
         * 	系统会再次校验线程池状态,在线程池已终止时会从队列中移除刚刚的命令,且调用拒绝策略通知调用者。或者启动一个新的非核心线程,
         * 	用于执行当前任务(所以线程是否终止咱们要反复确认的)
         *
         * 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.
         * 
         * 3.如果任务无法成功加入队列,系统会尝试创建一个非核心线程来执行该任务。如果创建失败,
         * 	那么不是线程池已饱和(包括核心线程数、队列、非核心线程数)就是线程池已终止,直接调用拒绝策略来通知调用者拒绝该任务
         */
        // 1、获取控制器
        int c = ctl.get();
        // 2、获取当前工作线程数量(当前工作线程数小于核心线程数会走第一个逻辑)
        if (workerCountOf(c) < corePoolSize) {
        	// 2.1、尝试直接增加核心工作线程,若增加成功直接返回(不放队列,直接把任务转交给核心线程了。里面会标记实际线程的第一次任务)
            if (addWorker(command, true))
                return;
            // 2.2、创建核心工作线程失败则继续走后续逻辑,先获取一下线程池当前控制器
            c = ctl.get();
        }
        // 3、同样先校验是否正在运行,并且任务入列是否成功,不成功直接走另一个逻辑
        if (isRunning(c) && workQueue.offer(command)) {
        	// 3.1、二次检查运行状态
            int recheck = ctl.get();
            // 3.2、当前线程池不是处于运行中的话,尝试从队列中清掉刚刚的任务(毕竟线程池都停止了,队列里面任务没啥用了)
            if (! isRunning(recheck) && remove(command))
            	// 3.3、清除成功的话调用拒绝策略通知调用者(人家把任务给你了,你给扔掉了,总要通知人家一声)
                reject(command);
            // 3.4、没有清除成功校验一下当前工作线程是不是已经为空了
            // 注意一点:正常情况下这里不会为空的,除非你的核心线程数配置了0,且所有工作线程的空闲时间都超过了配置的keepalivetime的值而被销毁了
            else if (workerCountOf(recheck) == 0)
            	// 3.5、创建一个非核心线程空转(用于把队列中刚刚放进去的任务消耗掉)
                addWorker(null, false);
        }
        // 4、尝试创建非核心线程执行任务(这里就是核心线程数及最大线程数的区别了,核心线程满了放队列,队列也满了就创建非核心工作线程)
        else if (!addWorker(command, false))
        	// 非核心线程也创建失败的话,直接调用拒绝策略通知调用者,这活儿我干不了了
            reject(command);
        // 从上面的代码逻辑来看,提交任务时线程池的逻辑是 核心线程数未满则创建核心工作线程并执行当前任务(正常情况下不入列)>尝试放入队列(不创建非核心线程)>尝试创建非核心线程(工作线程总数大于核心线程数配置,且队列已满) 这么个顺序。但仅第一波是这样的逻辑哈,一旦非核心线程被创建了,执行完本次任务以后,会再次尝试获取下一个任务的,这时候如果队列里面始终有任务,非核心工作线程也不会被销毁,直到队列没有任务,非核心工作线程空闲下来,且超过keepalivetime以后才会被销毁
    }

线程实例化-添加线程池内的工作线程(这才是真正的线程)

/**
     * Checks if a new worker can be added with respect to current
     * pool state and the given bound (either core or maximum). If so,
     * the worker count is adjusted accordingly, and, if possible, a
     * new worker is created and started, running firstTask as its
     * first task. This method returns false if the pool is stopped or
     * eligible to shut down. It also returns false if the thread
     * factory fails to create a thread when asked.  If the thread
     * creation fails, either due to the thread factory returning
     * null, or due to an exception (typically OutOfMemoryError in
     * Thread.start()), we roll back cleanly.
     *
     * @param firstTask the task the new thread should run first (or
     * null if none). Workers are created with an initial first task
     * (in method execute()) to bypass queuing when there are fewer
     * than corePoolSize threads (in which case we always start one),
     * or when the queue is full (in which case we must bypass queue).
     * Initially idle threads are usually created via
     * prestartCoreThread or to replace other dying workers.
     *
     * @param core if true use corePoolSize as bound, else
     * maximumPoolSize. (A boolean indicator is used here rather than a
     * value to ensure reads of fresh values after checking other pool
     * state).
     * @return true if successful
     */
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
        	// 获取控制器实例
            int c = ctl.get();
            // 获取当前运行状态
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 校验当前运行状态是否为不可继续运行状态,若状态为不可运行,则直接返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
            	// 获取当前工作的线程数
                int wc = workerCountOf(c);
                // 如果当前工作线程数已为线程池可容纳最大线程数,
                // 或者当前线程数大于等于想要创建的工作线程类型对应配置值(核心线程与非核心线程),
                // 直接返回false
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 尝试给控制器的当前工作线程数+1,若成功则跳出循环,执行后续逻辑
                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
            }
        }

    	// 标记工作线程是否启动
        boolean workerStarted = false;
        // 标记工作线程是否添加成功
        boolean workerAdded = false;
        // 工作线程实例(**************线程复用主要靠得就是这个对象了*****************)
        Worker w = null;
        try {
        	// 创建工作线程实例(外部传递的仅仅是Runnable、Callable或Thread类型的对象,仅仅是java对象而已,并不是系统级的线程)
        	// 这里大家一定要仔细理解,之前讲过很多次,很多人还是以为传递进来的命令对象就已经是系统级的线程了
        	// 实际并不是这样,外部传递的仅仅是一个普通的java对象而已,跟自定义bean没啥区别
            w = new Worker(firstTask);
            // 获取创建线程池中实际的线程(这个才是线程池内部实际运行的线程对象,跟操作系统对接的线程对象)
            // 该对象在Worker的构造函数中创建
            final Thread t = w.thread;
            // 获取失败则代表创建线程对象失败了,上面的两个默认标记都是false
            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());

                    // 当前为可运行状态,或当前线程池已被标记关闭,但待处理任务已经传递进来,
                    // 已传递进来的任务会继续执行,所以线程池啥时候停止不一定呢
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                    	// 如果新创建的线程正在运行,新创建的线程正在运行就代表状态异常(刚创建还没调用启动方法,不应该为存活),抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 把当前的工作线程加入线程池的工作线程集
                        workers.add(w);
                        int s = workers.size();
                        // 更新线程池最大线程数(外部可直接通过该参数获取线程池内的工作线程数)
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        // 标记工作线程添加成功(添加成功不代表启动成功)
                        workerAdded = true;
                    }
                    //释放线程池对象锁
                } finally {
                    mainLock.unlock();
                }
                // 只有当工作线程对象添加成功时才会尝试启动线程
                if (workerAdded) {
                	// 调用线程对象的启动方法
                    t.start();
                    // 标记工作线程启动成功
                    workerStarted = true;
                }
            }
        } finally {
        	// 未启动成功时,清理失败的工作线程实例,会从工作队列集中删掉该对象
            if (! workerStarted)
                addWorkerFailed(w);
        }
        // 返回工作线程对象是否添加成功
        return workerStarted;
    }

工作线程的执行逻辑

final void runWorker(Worker w) {
    	// 获取当前线程对象
        Thread wt = Thread.currentThread();
        // 缓存待执行的任务(调用线程池的execute或submit提交的任务)
        Runnable task = w.firstTask;
        // 清空对象缓存的待执行任务(后续该对象的第一次任务已经标记为空,就可以实现线程复用了)
        w.firstTask = null;
        // 释放自己的对象锁(允许外部调用中断操作,因为中断时会先尝试获取工作线程锁,这里不释放会导致那里无法加锁)
        // 为啥要释放锁呢?因为下面可能会存在工作线程长时间未获取待执行任务,处于空闲状态的情况。
        w.unlock(); // allow interrupts
        // 突然完成的标记(称之为异常终止标记比较合适,代表任务未成功按预期逻辑执行)
        boolean completedAbruptly = true;
        try {
        	// 前者是判断任务是否为工作线程实例化后第一次运行(不为空则代表第一次进入)
        	// 后者是从线程池的队列中获取待执行的任务(线程复用就在这里神奇的实现了)
            while (task != null || (task = getTask()) != null) {
            	// 确认要执行前,先给工作线程加锁
                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
                // 正式运行前,校验一下线程池状态,如果线程池状态为已停止,
                // 或者主进程已标记停止,且工作线程未标记停止,则尝试停止工作线程
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                	// 调用任务执行前置方法(所以可以继承ThreadPoolExecutor,在自己的实现类里面重载该方法做一些特殊处理)
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	// 调用任务实例的run方法(这里才是提交给线程池的线程任务对象有用的地方,只是为了让所有任务都有这个方法,好在这里调用)
                    	// 原来咱们自己创建循环处理的任务时会使用new Thread ... while(true) {dosomething 休眠并执行下一次}
                    	// 跟这里的逻辑没啥本质上的差异
                        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 {
                    	// 调用任务执行后置方法(所以可以继承ThreadPoolExecutor,在自己的实现类里面重载该方法做一些特殊处理)
                        afterExecute(task, thrown);
                    }
                } finally {
                	// 执行完毕后清空当前任务标记
                    task = null;
                    // 给工作线程的完成任务计数器+1
                    w.completedTasks++;
                    // 解锁本对象,进行下一次循环(死循环在这里)
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
        	// 执行工作线程退出前的一些通用逻辑(给整个线程池已完成任务计数器计数,把当前线程从工作线程集中清除)
        	// 线程异常终止恢复机制就在这个方法里面了(这里会置换异常线程实例)
            processWorkerExit(w, completedAbruptly);
        }
    }

线程复用

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())) {
            	// 给工作线程计数器-1
                decrementWorkerCount();
                return null;
            }

            // 获取线程池当前工作线程数
            int wc = workerCountOf(c);

            // Are workers subject to culling?
            // 是否需要校验工作线程超时销毁的标记(其实,核心线程只是当前保留的线程数而已,线程本身没有被标记是否为核心)
            // 允许核心线程超时销毁,或者当前存活的工作线程超过了核心线程数
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            // (工作线程超过了最大线程数,或者超时销毁标记为真,且获取任务超时)
            // (并且工作线程数大于1,或者任务队列已处于空的状态)
            // 同时满足以上两个条件会直接返回null(getTask的地方遇到null会销毁当前工作线程)
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	// 根据工作线程是否超时销毁标记来确认从队列中获取任务的策略
            	// 为真则调用poll,超时则标记已超时,并运行下一次循环判断
            	// 为假则调用take,死等(这时候外部工作线程不会被销毁,死等,就实现了核心线程数始终存活的逻辑)
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                // 成功拿到任务则返回该任务
                if (r != null)
                    return r;
                // 标记超时(下一次就会满足timedOut条件,非核心线程会被销毁)
                timedOut = true;
            } catch (InterruptedException retry) {
            	// 获取任务异常则不处理,继续下一次循环判断
                timedOut = false;
            }
        }
    }

3.2、线程终止

逻辑停止

/**
     * Initiates an orderly shutdown in which previously submitted
     * tasks are executed, but no new tasks will be accepted.
     * Invocation has no additional effect if already shut down.
     *
     * <p>This method does not wait for previously submitted tasks to
     * complete execution.  Use {@link #awaitTermination awaitTermination}
     * to do that.

执行该方法时会先有序的关闭当前线程池中的空闲的线程,标记线程池为关闭状态,不再接受新任务,
         * 	正在运行的任务不受影响(允许重复调用)。但是之前已提交未运行的任务不会被继续执行(也就是队列中还没来得及运行的任务不会继续运行)
     *
     * @throws SecurityException {@inheritDoc}
     */
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

强制停止

/**
     * Attempts to stop all actively executing tasks, halts the
     * processing of waiting tasks, and returns a list of the tasks
     * that were awaiting execution. These tasks are drained (removed)
     * from the task queue upon return from this method.
     *
     * <p>This method does not wait for actively executing tasks to
     * terminate.  Use {@link #awaitTermination awaitTermination} to
     * do that.
     *
     * <p>There are no guarantees beyond best-effort attempts to stop
     * processing actively executing tasks.  This implementation
     * cancels tasks via {@link Thread#interrupt}, so any task that
     * fails to respond to interrupts may never terminate.

与shutdown的区别:该方法会尝试停止池子中所有存活的线程,而shutdown只会终止空闲的线程。所以想停止线程池时,要根据自己实际的情况选择调用shutdown还是shutdownNow
     *
     * @throws SecurityException {@inheritDoc}
     */
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

3.3、线程池中任务处理顺序

3.3.1 核心线程数非0

先尝试创建核心线程并执行任务
核心线程数已满,且均繁忙则将任务加入队列(正常情况下队列未满不会直接创建非核心线程)
入列失败则尝试创建非核心线程直接去执行该任务(顺序的,自上而下,所以入列失败的前提是核心线程已满且繁忙)
创建非核心线程失败时则调用拒绝策略,通知线程池调用者

3.3.2 核心线程数为0,且当前工作线程数量为0(第一次启动或所有非核心线程均已被销毁)

加入队列并创建非核心线程执行该任务(因为不存在核心线程数,所以3.3.1中的第一条规则不生效。且同时做了3.3.1中的第二条规则和第三条规则)
创建非核心线程失败时则调用拒绝策略,通知线程池调用者

3.3.3 核心线程数为0,且当前工作线程数量大于0(3.3.2创建了非核心线程,且工作线程一直未被销毁)

将任务加入队列(正常情况下队列未满不会直接创建非核心线程)
入列失败则尝试创建非核心线程直接去执行该任务(顺序的,自上而下)
创建非核心线程失败时则调用拒绝策略,通知线程池调用者

四、结语

请使用线程池替代所有的new Thread().start()

尽量不要使用Executors直接创建线程池

实例化线程池时一定要知道每个参数的作用,并根据自己实际情况实例化适合自己的线程池

先学会用,再问为什么要这样用,最后问这样用的原理是什么,自己是否能把核心代码写出来。不要仅仅停留在会用层面,会用很可能仅仅是咱们自己层面的会用

平常没事儿多看看大牛写的代码,真的是长知识呀!

人家把饭都做好并且都要喂嘴里,就等咱们张口就吃了,如果咱们还非得自己去学做饭,有点儿多此一举了。

猜你喜欢

转载自blog.csdn.net/leandzgc/article/details/103111658