ThreadPoolExecutor详解

ThreadPoolExecutor阅读笔记

一、简介

JDK常用的线程池,里面有一个内部Worker类继承了AQS实现了Runnable

二、继承关系图

1578907461830

三、存储结构

  • 核心线程
  • 最大线程(超过核心线程的加入队列)
  • 超时时间
  • 线程工厂
  • 拒绝策略

四、源码分析

内部类
Worker
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
    private static final long serialVersionUID = 6138294804551838833L;

    /** Thread this worker is running in.  Null if factory fails. */
    // 真正工作的线程
    final Thread thread;
    /** Initial task to run.  Possibly null. */
    // 第一个任务,从个构造方法传进来
    Runnable firstTask;
    /** Per-thread task counter */
    // 完成任务数
    volatile long completedTasks;

    /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
    // 构造方法
    Worker(Runnable firstTask) {
        // 设置为等待唤醒状态
        setState(-1); // inhibit interrupts until runWorker
        // 第一个任务
        this.firstTask = firstTask;
        // 使用线程工厂生成一个线程
        // 注意,这里把Worker本身作为Runnable传递给线程工厂
        this.thread = getThreadFactory().newThread(this);
    }

    /** Delegates main run loop to outer runWorker  */
    // 实现Runbale的run方法
    public void run() {
        // 调用ThreadPoolExecutor的runWorker()方法执行线程
        runWorker(this);
    }

    // Lock methods
    //
    // The value 0 represents the unlocked state.
    // The value 1 represents the locked state.

    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    public void lock()        { acquire(1); }
    public boolean tryLock()  { return tryAcquire(1); }
    public void unlock()      { release(1); }
    public boolean isLocked() { return isHeldExclusively(); }

    void interruptIfStarted() {
        Thread t;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}
属性
*******************************************************************
/**
 * 下面都是线程池的生命周期的属性 
 *
 */

// 初始状态为RUNNING
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;

/*** 线程池的状态 ***/

private static final int RUNNING    = -1 << COUNT_BITS;
// 执行shutdown()后会把状态修改为SHUTDOWN
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 执行shutdownNow()方法时,会把线程池修改为stop状态,同时标记所有线程为中断状态
private static final int STOP       =  1 << COUNT_BITS;
// 当执行shutdown()或shotdownNow()之后,所有任务中已中止,且工作线程数量为0,就会进入这个状态
// tryTerminate() 函数中可见
private static final int TIDYING    =  2 << COUNT_BITS;
// 修改状态为TIDYING后执行terminated()方法,最后修改状态为TERMINATED,标志线程真正消亡了
// tryTerminate() 函数中可见
private static final int TERMINATED =  3 << COUNT_BITS;


*******************************************************************


/**
 * 任务队列(构造参数之一)
 * 当正在运行的线程数大于或等于核心线程的时候,任务来了先进入任务队列中的
 * 这个队列必须是阻塞队列,所以像ConcurrentHashMap就不能作为参数
 * ConcurrentHashMap是线程安全的队列,但是不是阻塞队列
 */
private final BlockingQueue<Runnable> workQueue;

private final ReentrantLock mainLock = new ReentrantLock();

/**
 * 处于运行中的线程数量
 * 例如判断运行中的线程数量是否大于等于核心线程,如果是,那就入任务队列
 */
private final HashSet<Worker> workers = new HashSet<Worker>();

private final Condition termination = mainLock.newCondition();
/** 工作线程历史最大数量:也是线程池 同时处于运行中的线程数量最大是多少 */
private int largestPoolSize;
/** 正常完成的任务数量:也是线程池 正常完成的线程数量	*/
private long completedTaskCount;

/**  
 * 线程工厂 (构造参数之一)
 * {@link java.util.concurrent.Executors}
 * 默认使用的是Executors工具类中的DefaultThreadFactory类,
 * 这个类有一个缺点,创建的线程名称是自动生成的,无法自定义以区别不同的线程
 * 并且这个类都是非守护线程
 * 如果要自定义工厂,可以自己实现一个ThreadFactory工厂,然后把名称和守护线程作为构造方法当参数
 */
private volatile ThreadFactory threadFactory;

/**
 * 拒绝策略(构造参数之一)
 * 		拒绝策略表示当任务队列满了且线程数也达到最大了,这时候再新加任务,线程池已经无法承受了,
 * 这些新来的任务应该按什么逻辑来处理
 *		常用的拒绝策略有丢弃当前任务、丢弃最老的任务、抛出异常、调用者自己处理等待
 *		默认的拒绝策略是抛出异常,即线程池无法承载了,调用者再往里面添加任务会抛出异常
 *		默认的拒绝车辆虽然比较简单粗暴,但是相对丢弃任务策略明显要好很多,最起码调用者
 *自己可以捕获这个异常在进行二次处理
 */
private volatile RejectedExecutionHandler handler;
/**
 * 线程保持空闲时间(构造参数之一)
 * 默认情况下,此参数仅当正在运行的线程大于核心线程时才有效,即针对非核心线程
 * 但是,如果allowCoreThreadTimeOut被设置了true,针对核心线程也有效
 * 即当任务队列为空时,线程保持多久才会销毁,
 * 内部主要通过阻塞队列待超时的poll(timeout,unit)方法来实现
 */
private volatile long keepAliveTime;

// 是否允许核心线程设置超时,默认是不允许
private volatile boolean allowCoreThreadTimeOut;
/** 
 * 核心线程数(构造参数之一)
 * 当正在运行的线程数小于核心线程时,来一个任务就创建一个核心线程
 * 当正在运行的线程大于或等于核心线程数时,任务来了先不创建线程而是丢入阻塞任务队列中
 */
private volatile int corePoolSize;
/**
 * 最大线程数(构造参数之一)
 * 当任务队列满了时,来一个任务才创建非核心线程,但不能超过最大线程数
 */
private volatile int maximumPoolSize;
/**
 * 默认的拒绝策略,任务满了会直接抛出RejectedExecutionException异常
 * (构造参数之一)
 */
private static final RejectedExecutionHandler defaultHandler =
    new AbortPolicy();
private static final RuntimePermission shutdownPerm =
    new RuntimePermission("modifyThread");
private final AccessControlContext acc;
构造方法
  • 四个构造方法
/** 初始化构造方法一:采用默认线程工厂和默认拒绝策略,其他自定义 */
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;
}
//{@link java.util.concurrent.Executors.DefaultThreadFactory}
// 默认线程工厂
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    // 线程组
    private final ThreadGroup group;
    // 线程池名称自增
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    // 线程池名称前缀
    private final String namePrefix;

    DefaultThreadFactory() {
        // 获取安全管理器
        SecurityManager s = System.getSecurityManager();
        // 如果安全管理器不为null就获取安全管理器中的线程组,否则获取当前线程的线程组
        group = (s != null) ? s.getThreadGroup() :
        Thread.currentThread().getThreadGroup();
        // 初始化线程池名称前缀
        namePrefix = "pool-" +
            poolNumber.getAndIncrement() +
            "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            // 设置守护线程为 无
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            // 设置默认线程优先级为 5
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
主要方法
1、线程池生命周期的方法
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvJtecD1-1579166492728)(img]

  • )

  • shudown() 关闭线程池

  • shudownNow() 立即关闭线程池

  • tryTerminate() 尝试终止线程池

// 线程池的状态
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 线程池中工作线程的数量
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 计算ctl的值,等于运行状态“加上” 线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; }

/** 关闭线程池,自旋+CAD所以一定可以关闭,并把所有线程设置为中断状态 */
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    // 加 主锁
    mainLock.lock();
    try {
        // 检查权限
        checkShutdownAccess();
        // 修改状态为SHUTDOWN,采用自旋+CAS
        advanceRunState(SHUTDOWN);
        // 标记空闲线程为中断状态
        interruptIdleWorkers();
        // 为ScheduledThreadPoolExecutor 预留的
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        // 释放主锁
        mainLock.unlock();
    }
    
    tryTerminate();
}
private void advanceRunState(int targetState) {
    for (;;) {
        int c = ctl.get();
 		// 如果状态大于SHUDOWN,或者修改SHUTDOWN成功了,才会break出自旋
        if (runStateAtLeast(c, targetState) ||
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

/** 立即关闭线程池*/
public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    // 加 主锁
    mainLock.lock();
    try {
        // 权限检查
        checkShutdownAccess();
        // 自旋+CAS 让线程进入STOP状态
        advanceRunState(STOP);
        // 标记空闲线程为中断状态
        interruptWorkers();
        // 把任务队列加入到一个新的队列保存到 tasks
        tasks = drainQueue();
    } finally {
        // 释放主锁
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

/**  */
final void tryTerminate() {
    for (;;) {
        // 获得线程池状态
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            // 1.如果线程池是RUNNING状态
            // 2.如果线程池是TIDYING或TERMINATED状态
            // 3.如果是SHOTDOWN状态且任务队列不为空
            // 符合上面任何一点,则直接返回,不进入下面代码
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            // 工作线程数量不为0,
            // 尝试中断空闲线程,然后直接返回
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        // 加主锁
        mainLock.lock();
        try {
            // CAS更新修改状态为TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // 更新成功,执行terminated()钩子方法
                    terminated();
                } finally {
                    // 强制更新状态为TERMINATED,这里不用CAS
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            // 释放主锁
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}
2、线程的执行方法
  • execute():线程池提交任务的方法之一,也是最核心的方法,会根据核心线程数量、最大数量、任务队列大小,
    • 先进行添加核心线程(添加到线程HashSet集合,此次会考虑容量),添加成功就会采用核心线程方式CAS启动任务
    • 如果添加失败,那么就加入等待队列
      • 加入任务队列成功,就会去CAS添加非核心线程(添加到线程HashSet集合,此次会考虑容量),添加成功,然后就会启动一次线程(加锁启动),启动失败就直接删除添加到HashSet集合中的线程
    • 如果加入任务队列也失败,就会去CAS添加非核心线程(添加到线程HashSet集合),添加成功,然后去启动一次线程(加锁启动),如果启动失败,就直接采用拒绝策略
    • 根据上面情况总结
      • 只要能加入队列,那么任务早晚会被运行,也不会被拒绝。
      • 加入队列也失败,只要线程加入到工作线程集合,启动一次任务还是失败,那么肯定采用拒绝策略了
  • addWorker():创建一个工作线程,并去启动,会做各种线程池状态和工作线程数量检测
    • 这里会做线程池最大容量检查,true检查核心数量,false检查最大容量,如果不符合要求就会直接返回(但是如果加入到队列的话,是不影响的,所以LinkedBlockingQueue无界的,那么是没有容量限制的,maxSize是无效的)
  • runWorker() :真正执行任务的方法
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.
         */
    int c = ctl.get();
    // 1、如果线程少于 corePoolSize,尝试以给定的命令作为第一个任务启动新线程,对于 addWorker 的调用原子地检查 runState 和 workerCount,从而通过返回 false 来防止不应该添加线程的情况下发出错误警报;
    if (workerCountOf(c) < corePoolSize) {
        // 添加一个工作线程(核心)
        if (addWorker(command, true))
            // 核心线程已启动,返回成功
            return;
        // 添加工作线程(核心)失败,重新获取控制变量
        c = ctl.get();
    }
    // 2、如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为现有线程自上次检查后就已死亡)或自进入此方法以来池已关闭。因此,我么重新检查状态,如果停止,并在必要时回滚排队,如果已停止,或者再没有线程的情况下启动新线程;
    if (isRunning(c) && workQueue.offer(command)) {
        // 达到了核心线程最大数量,且线程池也是运行状态,就任务入队列
        
        // 重新获取线程池状态,防止进入任务后线程池关闭
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            // 重新检查线程状态不是运行状态,就从工作队列中删除,然后抵达都用拒绝策略
            reject(command);
        else if (workerCountOf(recheck) == 0)
            // 容错检查,工作线程数量是否为0,如果为0就创建一个
            addWorker(null, false);
    }
    // 3、如果无法将任务排队,则尝试添加一个新线程,如果失败了,我们知道我们被关闭或已达到最大线程,因此拒绝该任务
    // 任务入队列失败,尝试创建工作线程(非核心),失败则拒绝
    else if (!addWorker(command, false))
        reject(command);
}

/**
 * 加入工作线程
 * core代表加入的是 核心线程还是非核心线程
 */
private boolean addWorker(Runnable firstTask, boolean core) {
    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;
		//循环检查数量及对工作线程数量+1
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                // 工作线程数量检查
                return false;
            if (compareAndIncrementWorkerCount(c))
                // 尝试更新数量,成功跳出自定义标记块retry
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                // 再次获取状态
                // 如果线程池状态有变化,跳过不执行下面代码(如果有的话),然后重新for循环
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }
	// 如果上面的条件满足,会把工作线程数量+1
    
    boolean workerStarted = false;// 标记线程是否已经启动成功,如果没成功会执行移除方法
    boolean workerAdded = false;//标记添加到Woker的HashSet工作集合是否成功,成功了才启动线程
    Worker w = null;
    try {
        // 创建一个工作线程(Worker继承了AQS,实现了Runnable)
        w = new Worker(firstTask);
        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());
			   
                // 再次检查线程池状态
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    
                    // 检测线程是否已经激活(启动),如果启动抛出IllegalThreadStateException异常
                    if (t.isAlive()) // precheck that t is startable    
                        throw new IllegalThreadStateException();
                    // 加入到HashSet工作线程集合中
                    workers.add(w);
                    
                    // 获取工作线程集合数量(largestPoolSize只可在主锁下使用)
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 标记添加成功
                    workerAdded = true;
                }
            } finally {
                // 释放-主锁
                mainLock.unlock();
            }
            if (workerAdded) {
                // 启动线程,此处执行的是Worker里面的run(),
                // Worker类中的run调用的是runWorker();
                t.start();
                // 设置为已启动
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            // 线程启动失败,执行失败方法
            //移除Woker的HashSet中的w线程,如果有的话,数量-1,tryTerminate()方法等
            addWorkerFailed(w);
    }
    // 返回启动状态,true 成功,false 失败
    return workerStarted;
}

/**
 * Worker线程类,run()方法中调用此方法进行启动线程
 */
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();//当前线程
    Runnable task = w.firstTask;//缓存当前待运行线程
    w.firstTask = null;//GC
    // 强制释放锁,(shutdown()里面有加锁)
    // 相当于无视那边的中断标记
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;// 是否突然完成了
    try {
        // 如果参数的Woker线程中的任务线程是null,就会直接从队列中获取
        // 只要还能取到任务,这就是一个死循环
        while (task != null || (task = getTask()) != null) {
            // 对当前Work加锁
            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 {
                // 钩子方法,方便子类在任务执行前做一些逻辑,由子类自己来实现
                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,然后重新从队列中获取
                task = null;
                // 任务执行完成,就completedTasks加1
                w.completedTasks++;
                // 释放当前work线程锁
                w.unlock();
            }
        }
        completedAbruptly = false;// 没有突然完成,正常完成了任务
    } finally {
        // 到这里要么是突然完成,要么是正常完成了队列的任务,
        // 如果是突然完成的(也就是其他地方完成 或者是异常了等情况),就会直接减少ctl值
        // 如果是正常完成,就更新completedTaskCount值,并移除worker集合中当前的worker
        // 等等其他逻辑
        processWorkerExit(w, completedAbruptly);
    }
}

/*
 * {@link java.util.concurrent.ThreadPoolExecutor#runWorker(ThreadPoolExecutor.Worker)}
 * 从任务队列中获取任务线程
 */
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.如果线程池关闭了且线程池已经停止了,说明线程是STOP状态,立即退出
            // 2.如果线程池关闭了,且任务队列为null,没有任务了直接立即退出
            // 符合上面任何一点就,CAS修改Woker集合数量-1,然后返回null
            decrementWorkerCount();
            return null;
        }

        // 获得工作线程数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?
        // 是否允许超时机制
        // 1、核心线程 配置了allowCoreThreadTimeOut=true
        // 2、工作线程数量超过了核心线程数量
        // 注意:非核心线程是一定有超时的,这里的超时其实是指取任务的超时
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
		
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 超时了,减少工作线程数量 ,并且返回 null
            if (compareAndDecrementWorkerCount(c))
                return null;
            // 减少工作数量失败,就重试
            continue;
        }

        try {
            // 真正开始取任务了,
            // 会根据timed来确定采用 poll超时 还是take进行阻塞等待任务			
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
            workQueue.take();
            if (r != null)
                // 获得到了任务,直接返回任务
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            // 捕捉到了中断异常,
            // 中断标记是在调用shutdown()或shutdownNow()的时候设置进去的
            // 此时,会回到for循环的第一个if处判断线程池状态,是否要返回null
            timedOut = false;
        }
    }
}
3、提交线程
  • 都是父类-抽象类AbstractExecutorService的方法
  • 三个不同的submit方法
/** 提交线程,并且执行execute,返回Future,或者不返回 */
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    //等于new FutureTask<T>(callable),把普通任务包装成FutureTask
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}
/** 提交线程,并且执行execut,返回Future<?> */
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);//见下
    execute(ftask);
    return ftask;
}
/** 提交线程,并且执行execute,返回包装了result的future,或不返回 */
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;
}

{@link java.util.concurrent.futureTask 的构造方法}
public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
}
{@link java.util.concurrent.Executors#callable}}
public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}
{@link java.util.concurrent.Executors.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;
    }
}
补充

五、总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值