并发包源码解读——ThreadPoolExecutor线程池

并发包源码解读——ThreadPoolExecutor线程池


以一个简单的例子开始

//核心线程数,保持池内最少存活N个线程
        int corePoolSize = 5;
        //最大线程数,限制池内最多存活N个线程
        int maximumPoolSize = 5;
        //线程空闲时间,当池内线程空闲一段时间会自动销毁,但不会小于核心线程数
        long keepAliveTime = 1000;
        TimeUnit unit = TimeUnit.MILLISECONDS;
        //阻塞队列,限制存放等待获取线程资源的最大任务数
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5);
        ThreadFactory threadFactory = Thread::new;
        //任务拒绝策略,当阻塞队列中任务堆满、无法入队后执行的逻辑
        RejectedExecutionHandler handler = (r, executor) -> System.out.println("任务被拒绝了");
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler);
        for (int i = 0;i<100;i++){
            int finalI = i;
            System.out.println("准备执行"+ finalI);
            executor.execute(() -> {
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            System.out.println("执行完成"+ finalI);
        }
        do {
            if(!executor.isShutdown()){
                executor.shutdown();
            }
        } while (!executor.isTerminated());
    }

1、构造器

就是初始化各种参数

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、execute——执行

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
		//32-3=29
    private static final int COUNT_BITS = Integer.SIZE - 3;
		//低29位表示线程池内的线程个数,感觉跟ReentrantReadWriteLock的实现方式比较像
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
		//高3位表示线程状态
		//111
    private static final int RUNNING    = -1 << COUNT_BITS;
		//000
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
		//001
    private static final int STOP       =  1 << COUNT_BITS;
		//010
    private static final int TIDYING    =  2 << COUNT_BITS;
		//011
    private static final int TERMINATED =  3 << COUNT_BITS;
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
  			//执行的任务不能为空
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
  			//取低29位线程数,如果执行任务时池内线程比核心线程数少,就加一个核心线程	
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
  			//如果线程池内线程数已经达到了核心线程数,或者线程增加失败了,就检查线程池运行状态,将任务放入队列
  			//增加线程失败的原因可能是池内线程数达到了核心线程数、线程没有放进HashSet中、或者线程没有启动成功等
        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);
    }

2.1、addWorker——向池内加线程

往线程池内加线程调用addWorker方法

//线程池是一个HashSet
private final HashSet<Worker> workers = new HashSet<Worker>();
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;

        for (;;) {
            int wc = workerCountOf(c);
          	//线程池内线程数已经比核心线程数多,就不再向线程池增加线程了
          	//如果加的不是核心线程,就要跟最大线程数比一下
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
          	//cas让线程池内线程数加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 {
      	//创建一个线程,用来放到线程池内
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
          	//增加线程池内线程通过ReetrantLock实现
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
              	//取高3位运行状态
                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();
            }
          	//新建的线程成功放到线程池中了,就启动它
          	//注意Worker是实现Runnable接口的,启动后会调用run方法
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
      	//无论什么原因,只要线程启动失败
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

创建一个新线程Worker,构造器是这样的

Worker(Runnable firstTask) {
  					//这个时候偶线程还没运行,先设置-1
            setState(-1); // inhibit interrupts until runWorker
  					//初始化这个线程要执行的任务
            this.firstTask = firstTask;
  					//调用自己实现的ThreadFactory
            this.thread = getThreadFactory().newThread(this);
        }

线程启动失败后调用addWorkerFailed维护线程池

private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
          	//线程加到线程池了,但是启动失败,要移除
            if (w != null)
                workers.remove(w);
          	//然后把线程数量改回去
            decrementWorkerCount();
          	//尝试停线程池
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
      	//如果线程在运行,或者已经停止、或者已经关了在等着阻塞队列中的工作完成
      	//这几种状态都不能关,直接返回
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;	
      	//如果线程池内还有线程,就尝试中断池内第一个线程
        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));
                  	//停止之后可以提前唤醒等待线程池停止的外部“主”线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

尝试中断线程调用interruptIdleWorkers,代码逻辑清晰就不赘述了

private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

2.2、remove——移除任务

移除任务的方法也比较简单,就是从队列中移除任务,然后尝试中断第一个线程

public boolean remove(Runnable task) {
        boolean removed = workQueue.remove(task);
        tryTerminate(); // In case SHUTDOWN and now empty
        return removed;
    }

2.3、reject——执行拒绝策略

执行拒绝策略调用reject方法,是rejectedExecution的封装

其实就是执行我们实现了RejectedExecutionHandler的方法

final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }

2.4、runWorker——让线程执行任务

Worker实现了Runnable接口,它的run方法是ThreadPoolExecutor中runWorker方法的封装

public void run() {
            runWorker(this);
        }
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
          	//从阻塞队列中取任务
            while (task != null || (task = getTask()) != null) {
                w.lock();
              	//根据线程池状态执行线程中断
                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;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
          	//回收线程池内线程
            processWorkerExit(w, completedAbruptly);
        }
    }
  private Runnable getTask() {
    boolean timedOut = false; 

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        //检查运行状态,如果线程池已经停了,或者准备停但是正在等阻塞队列任务全部完成
      	//符合上述条件,维护线程数,然后返回上一个方法执行processWorkerExit回收线程
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
				
        int wc = workerCountOf(c);

      	//超时的核心线程和超过核心线程数的线程会被回收
        //allowCoreThreadTimeOut表示是否允许核心线程空闲超时被回收,可以在初始化ThreadPoolExecutor时设置
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
				//线程池内线程数大于核心线程数,或者从阻塞队列中取任务超时了
      	//如果线程池内有线程或者阻塞队列是空的,就维护线程数减1,同样准备执行processWorkerExit回收线程
        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;
          	//没任务支持超时就在下一次for循环时回收
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

2.5、processWorkerExit——回收线程

getTask返回空时,当前线程要被回收

private void processWorkerExit(Worker w, boolean completedAbruptly) {
  			//当前线程执行任务失败了,就先维护线程数-1
        if (completedAbruptly)
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
          	//ThreadPoolExecutor全局维护一个completedTaskCount,用来记录完成的任务个数
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
				//尝试终止线程
        tryTerminate();

        int c = ctl.get();
  			//如果线程池在运行,或者准备停了,要恢复线程池内线程
        if (runStateLessThan(c, STOP)) {
          	//核心线程超时了,或者线程执行任务成功了
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
              	//核心线程允许超时回收,且阻塞队列不为空,那线程池应该至少有一个线程用来工作
              	//核心线程不允许超时回收,那线程池内应该有核心线程数个线程
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
              	//池内线程多与允许的最小线程,就不用增加线程
                if (workerCountOf(c) >= min)
                    return; 
            }
          	//池内线程少于允许的最小线程,就增加线程
            addWorker(null, false);
        }
    }

2.6、shutdown——停止线程池

调用shutdown停止线程池

public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
          	//首先调用checkShutdownAccess,这是跟SecurityManager有关的,一半SecuriityManager都为空不执行逻辑,不做介绍
            checkShutdownAccess();	
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

自旋修改线程池状态为SHUTDOWN,当线程池状态不是运行或准备关机的状态时才会CAS修改状态

private void advanceRunState(int targetState) {
        for (;;) {
            int c = ctl.get();
            if (runStateAtLeast(c, targetState) ||
                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
                break;
        }
    }

中断所有线程调用interruptIdleWorkers

private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }

3、总结

ThreadPoolExecutor底层用HashSet存线程,用BlockingQueue存任务

无论池内是否有空闲线程,任务到来时都会先进BlockingQueue

ThreadPoolExecutor是通过BlockingQueue的take方法实现任务监听的

池内核心线程是随着任务的到来而创建的,而并非线程池创建时就初始化核心线程。只要池内核心线程数不够,新来的任务都会创建新的线程来执行,然后被创建的线程会作为核心线程存在线程池中

线程池调用shutdown会先将线程池状态改成SHUTDOWN,等待所有任务执行完,然后再改成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wheat_Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值