线程池原理+JDK1.8源码解析

线程池创建的方式:

public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                              long keepAliveTime,
                               TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                               RejectedExecutionHandler handler) 

参数的介绍:

corePoolSize:线程池核心线程数

maximumPoolSize:线程池最大线程数

keepAliveTime:非核心线程数,空闲多久会被回收

unit:空闲时间的单位

workQueue:线程池等待队列的大小

handler:线程池达到饱和的策略处理类

线程池原理:

先看下面一张流程图:

è¿éåå¾çæè¿°

1.当一个任务过来时,先判断当前线程池的核心线程数是否已经创建满了

    如果没有满,直接创建线程,进行任务处理;如果满了,进入到第二步

    注意:这里即使当前创建过的线程有空闲的,依然会重新创建线程执行任务,而不是拿空闲线程来用。

2.判断当前的线程池队列是否满了,没有满,任务加入到队列中进行排队;如果满了,进入到第三步

3.判断当前线程池行程数量是否达到了最大线程数,如果没有达到,创建线程执行当前任务,如果达到了,进入第4步处理

4.按照配置的饱和处理策略,进行处理

JDK1.8源码解析:

先看ThreadPoolExecutor的内部状态实现方式:

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;

    // Packing and unpacking ctl
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }

我们可以看到这里有一个AtomicInteger类型的ctl 变量:int一共是32位,这里采用的是低位29位表示线程池线程的个数,高3位表示当前线程池的状态。

COUNT_BITS:我们看这个常量,它的值=32-3=29

RUNNING    = -1 << COUNT_BITS; 这里表示高3位是111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
SHUTDOWN   =  0 << COUNT_BITS;这里表示高3位是000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
STOP       =  1 << COUNT_BITS;这里表示高3位是001,该状态的线程池不会接收新任务,也不会处理阻塞队列中的任务,并且会中断正在运行的任务;
TIDYING    =  2 << COUNT_BITS;这里表示高3位是010,表示当前线程池所有任务都已经终止了;
TERMINATED =  3 << COUNT_BITS;这里表示高3位是011,表示erminated()方法已经执行完成 ;

运行流程解析:

1.ThreadPoolExecutor的execute方法

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();
        }
        //这里需要判断当前线程池的状态=RUNNING,并且把当前任务加入到任务队列里
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //如果线程池不是RUNNING状态,成功从阻塞队列中删除任务,执行reject方法处理任务
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //线程池处于running状态,但是没有线程,则创建线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //队列也满了,这个时候会创建非核心线程去执行任务  
        //如果失败,直接走饱和拒绝策略处理
        else if (!addWorker(command, false))
            reject(command);
    }

注意:这里做了双重检查,是因为多线程环境下,线程池的状态是随时变化的,而获取状态跟下面操作是非原子性的,如果不做双层check,可能会出现线程变成了非运行状态,结果却把任务放到了执行任务队列里,导致任务无法执行。且不会通知到调用端。

2.addwork()方法:主要是创建线程并执行任务

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果当前线程池状态是非运行状态并且
            //状态是shutdown状态而且任务不为空,队列是空的 直接return失败
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                //获取当前运行中的线程数
                int wc = workerCountOf(c);
                //线程数跟配置大小作比较
                //如果大于等于最大数  或者 通过传入的参数  来跟核心线程数和最大线程数做比较 当前线程数超过配置值时  直接return失败
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //通过CAS来增加当前线程池里线程的数量 修改成功  直接跳出当前循环
                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 {
            //创建一个Worker对象,传入当前的任务
            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());
                    //如果当前状态是运行中  或者 (是shutdown 并且任务为空的话)
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        //如果当前线程是已经运行中的  抛出异常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //一切正常  把当前worker加入到set中
                        workers.add(w);
                        //如果set的大小大于最大线程大小的时候 扩大当前值
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    //释放锁
                    mainLock.unlock();
                }
                //任务加入到worker成功  执行当前线程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

注意:这里在添加到set的时候,做了加锁处理,这里主要是需要准确判断当前线程池的状态,在此处执行的时候,不容许其他线程修改当前线程池的状态,已达到正确性。

3.worker.runWorker()方法,这个是执行任务的核心方法:

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        //这里是修改worker的状态  容许当前任务被线程池打断
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            //当前需要执行的任务不为空
            //这里用的是个while 如果传入的任务为空的话
            //会从线程池队列里拿出任务来处理
            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 {
                    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);
        }
    }

整体流程为:

1.获取当前任务;

2.线程启动之后,通过unlock方法释放锁,设置AQS的state为0,表示运行可中断; 

3.执行传入的任务,或者是直接从线程池的任务队列里面获取任务执行;

4.给当前线程加锁,保证不会被其他前程中断(如果线程池直接中断,这里也会中断);

5.检查当前线程池的状态,如果当前线程池是中断状态,这直接中断当前线程;

6.执行beforeExecute方法

7.执行当前任务的run方法

8.执行afterExecute方法 

9.解锁  容许被其他线程中断

4.我们看一下从任务队列里面获取任务的方法:getTask()

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;
            //如果当前线程数大于最大线程数 或者是达到了回收的条件
            //而且线程数量大于1 或者 任务队列已经空了
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                //如果线程不允许无休止空闲timed == true, workQueue.poll任务:如果在keepAliveTime时间内,阻塞队列还是没有任务,则返回null
                //如果线程允许空闲等待而不被销毁timed == false,workQueue.take任务:如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒,take方法返回任务,并执行;
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值