线程池ThreadPoolExecutor分析

线程池ThreadPoolExecutor分析

ThreadPoolExecutor是JDK线程池的核心类
线程池是用来管理线程的。用来应对正常情况下,线程执行完任务后不被销毁,继续执行其它的任务,减少创建线程,线程回收,减少线程的上下文切换成本。特殊情况下,任务突然激增,处理不过来先放入阻塞队列等待被处理,如果仍然处理不过来可以创建临时线程去处理任务,用户只需要设定上限即可

可以有异步执行的效果,比如发送短信,发送邮件,甚至使用MQ推送消息,也可以包装成任务丢到线程池中去异步处理



简介

1,在JDK提供的线程池中,有变量记录了线程执行任务的个数,以及整个线程池执行任务的个数
2,JDK线程池也提供了相应的钩子函数用于逻辑扩展,beforeExcute和afterExcute方法
beforeExcute:在每个任务执行前执行
afterExcute:每个任务执行后执行
3,特殊情况下,任务突然激增导致线程不够用会先将任务放入阻塞队列中,阻塞队列放满时如果仍然处理不过来则创建临时线程去处理,还处理不过来,就根据拒绝策略进行处理
(也正是因为这个特征,tomcat才会重写线程池,不会等待队列满时才创建临时线程,不然可能很多io请求直接堆积在队列中,即时性很差,可能还没执行请求就超时了)
4,有submit和execute两种提交方式,前者任务被futureTask类包装一下,用来封装任务的返回值


提示:以下是本篇文章正文内容,下面案例仅供参考

一、构造方法核心参数分析

    // corePoolSize: 核心线程数,执行完任务后不会被销毁,继续执行下一个任务
    // 如果allowCoreThreadTimeOut配置为true,则核心线程达到过期时间后,也会被销毁,该参数默认为false
    public ThreadPoolExecutor(int corePoolSize, 
   	// 线程池内最大线程数,队列满时任务处理不过来,会创建临时线程去处理,一直创建到池内线程数为该数量为止
                              int maximumPoolSize,
                              // 临时线程的存活时间,线程空闲并且过期后临时线程会被回收
                              long keepAliveTime,
                              // 过期时间的单位
                              TimeUnit unit,
                              // 存放任务的阻塞队列,需要注意无界队列内存溢出的风险
                              BlockingQueue<Runnable> workQueue,
							  // 线程工厂,创建线程用的。线程优先级默认为5
                              ThreadFactory threadFactory,
                              // 任务拒绝策略
                              RejectedExecutionHandler handler) {
        // 这个校验,意味着核心线程数可以配置为0
        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;
    }

1,RejectedExecutionHandle任务拒绝策略详情:
1.1,AbortPolicy:直接抛异常:RejectedExecutionException
1.2,CallewrRunsPolicy:交给提交任务的线程去处理这个任务
1.3,DiscardIldestPolicy:丢弃掉队列中最近的任务,执行当前任务
1.4,DiscardPolicy:对任务不做处理
2,allowCoreTreadCodeTimeout:该参数为true时,空闲的核心线程达到过期时间后,也会被销毁。默认为false

二、ThreadPoolExecutor核心属性分析

    // ctl的高三位代表线程池的状态
 	// ctl的低29位代表工作线程数的个数,最多支持5亿多个
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // 池内线程池个数的上限
    // 值:00011111 11111111 11111111 11111111 => 536870911
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // 线程池的5个状态
    // 高三位: 111(-536870912) 正常状态,可执行任务,可接受任务
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 高三位:000(0),执行shutDown()为该状态,不在接受新任务,将队列中的任务和正在执行的任务处理完后结束
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    // 高三位: 001(536870912),STOP状态,线程池即将关闭,阻塞队列的任务不在处理,正在处理任务的线程设置中断标志位
    private static final int STOP       =  1 << COUNT_BITS;
    // 高三位:010(1073741824),是一个过度状态,由SHUTDOWN或STOP转换过来,在执行terminated后进入TERMINATED状态
    private static final int TIDYING    =  2 << COUNT_BITS;
    // 高三位:011(1610612736),关闭状态
    private static final int TERMINATED =  3 << COUNT_BITS;

    // 以下方法入参是ctl
    // 拿到高三位的值:
    // 对CAPACITY进行取反: 00011111 11111111 11111111 11111111 => 11100000 00000000 00000000 00000000
    // 基于&运算,获取高三位的值:11100000 00000000 00000000 00000000 => 111
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    // 计算工作线程数,根据CAPACITY计算出低29位的值
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }
    
    /**
     * Tracks largest attained pool size. Accessed only under
     * mainLock.
     */
    private int largestPoolSize;

    // 任务完成数
    private long completedTaskCount;

状态库流转图:

线程池状态流转图

三、基本使用

    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(2),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r);
                    }
                }, new ThreadPoolExecutor.AbortPolicy());
        
        // 模拟100个任务
        for (int i = 0; i < 100; i++) {
            // 不能调用get方法,因为是阻塞方法,会等到任务执行完毕
            threadPoolExecutor.submit(() -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务:" + Thread.currentThread().getName());
            });
        }
    }

四、ThreadPoolExecutor核心方法分析

1.submit方法分析

代码如下:

    // 带有返回值的提交任务方法
    public Future<?> submit(Runnable task) {
    	// 任务不能为空
        if (task == null) throw new NullPointerException();
        // 用FutureTask包装一下任务,方便调用set方法封装返回值
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        // 提交任务
        execute(ftask);
        return ftask;
    }
    // ThreadPoolExecutor对execute方法的实现,没有返回值
    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;
            // 添加核心工作线程失败,重新获取ctl的值
            // 可能线程池状态发生了改变,也可能两个线程同时execute,但只有一个核心线程
            c = ctl.get();
        }
        // 如果线程池状态是RUNNING,往工作队列中添加任务
        if (isRunning(c) && workQueue.offer(command)) {
        	// 添加任务成功,再次获取ctl的值
            int recheck = ctl.get();
            // 再次判断是否是running状态,如果不是,从队列中删除这个任务
            if (! isRunning(recheck) && remove(command))
            	// 不在接收新任务,执行拒绝策略
                reject(command);
            // 线程池状态正常 || 队列删除失败
            // 如果工作线程数为0
            else if (workerCountOf(recheck) == 0)
            	// 添加一个非核心线程去处理队列中的任务,因为队列中有任务
            	// 通过这个判断可能是用户将核心线程数设置为0,或者配置了allowCoreThreadTimeOut为true
                addWorker(null, false);
        }
        // 线程池状态不正常 || 任务入队失败了(可能队列满了)
        // 创建非核心线程去处理任务
        else if (!addWorker(command, false))
        	// 如果失败,可能线程数满了或线程池状态改变了,执行拒绝策略
            reject(command);
    }

2.addWorker方法分析

添加工作线程,去执行任务

代码如下:

// 添加工作线程去处理任务
// core: 是否是核心线程
private boolean addWorker(Runnable firstTask, boolean core) {
		// 给外层死循环起个名字,这个循环全是校验逻辑
        retry:
        for (;;) {
            int c = ctl.get();
            // 高三位的值,获取线程池状态
            int rs = runStateOf(c);

            // SHUTDOWN:0
            // 如果线程池状态大于等于0,则状态可能是除了RUNNING外其他任何状态
            // 此时代表着不在接收任何外部任务
            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增加工作线程数
                if (compareAndIncrementWorkerCount(c))
                	// 校验结束
                    break retry;
                // CAS失败,再次判断线程池状态是否发生了改变,如果改变,继续校验
                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:设置state,保存任务,使用ThreadFactory创建线程
            w = new Worker(firstTask);
            // 从worker中获取线程
            final Thread t = w.thread;
            // 如果线程为null,可能是线程工厂创建线程时发生了问题
            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());
				
					// 如果小于0,则状态为Running状态
                    if (rs < SHUTDOWN ||
                    	// 状态不是running,可能是shutdown,结合execute方法,任务可能为null
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 此时线程还没有被start,如果已经开始执行了报错
                        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();
                }
                // 如果工作线程创建成功,调用Woker的runWorker方法,执行任务
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
        	// 如果工作线程启动失败,从workers中删除当前的worker
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

retry死循环,全是校验是否可以创建工作线程去执行任务

3.内部类Worker分析

    // 继承了AQS,实现了Runnable,重写了run方法,run方法中执行具体的任务
    private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
		// 执行任务的线程,执行run()后会跳转到Worker重写的run方法中,然后执行firstTask.run()
        final Thread thread;
        // 任务
        Runnable firstTask;
        // 完成任务数
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
        	// 状态设置为-1,根据interruptIfStarted方法可以判断,这个状态无法设置中断标志位
            setState(-1);
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        // 重写了run方法,去执行具体的任务
   		// 由于创建woker时将this传进去,其实执行线程的start时执行的是runWorker方法
        public void run() {
            runWorker(this);
        }

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

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

		// 修改state的值
        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(); }

		// 执行shutDownDnow,中断线程时 ,会先执行该方法
		// 设置中断标志位
        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

4.分析runWorker方法

执行任务,如果是非核心线程,或者核心线程也可以过期回收掉,或者线程池即将关闭则getTask返回null,线程结束,等待被回收掉
反之,执行获取到的任务,如果核心线程不能被回收,getTask会阻塞住,一直到获取到任务

 public void run() {
    runWorker(this);
 }
 // 执行任务
 final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        // 将state设置成0,意味着可以设置中断标志位
        w.unlock();
        boolean completedAbruptly = true;
        try {
        	// 任务为null时,从阻塞队列中获取任务,获取不到一直等待
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // 如果线程池状态大于等于STOP && 没有设置中断位 => 设置中断位
                // 如果线程被设置中断位(会恢复) && 线程池状态大于等于STOP && 没有设置中断位 => 设置中断位
                if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                	// 执行任务前先执行before钩子函数
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	// 启动线程。如果使用submit提交方式,会跳转到FutureTask重写的run方法中
                        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++;
                    // 将状态重新设置为0,此时shutDwon方法可以将当前线程设置中断位
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
        	// 判断是否清除当前工作线程
            processWorkerExit(w, completedAbruptly);
        }
    }

	// 如果使用了submit提交方式,会执行到FutureTask的run方法中
    public void run() {
    	// 是否是NEW状态
        if (state != NEW ||
        	// 是NEW状态,CAS将执行线程改成当前线程,如果失败,说明有其他执行这个任务
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            // 有其他线程执行这个任务
            return;
        try {
            Callable<V> c = callable;
            // 确保初始化了
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                	// 执行任务
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                // 任务执行结束,调用set方法封装返回结果,将结果赋值给了outcome参数
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

5.getTask方法分析

获取任务
1,如果是临时线程并且达到了过期时间仍然没有获取到任务,返回null,线程被回收掉
2,如果核心线程可以被回收,并且过期时间内没有获取到任务,返回null,线程被回收
3,线程池状态即将关闭,返回null
4,如果核心线程不能被回收,执行take方法,一直到获取到任务才能返回
5,如果是临时线程,执行poll(keepAliveTime, unit),如果获取到任务,则继续执行任务,获取不到线程被回收掉

	// 获取任务
	private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

		// 死循环
        for (;;) {
            int c = ctl.get();
            // 高三位,获取线程池状态
            int rs = runStateOf(c);

            // 线程池状态大于等于SHUTDOWN && (状态大于等于STOP || 没任务了)
            // 线程池即将关闭 || 没任务了
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            	// 工作线程数减一
                decrementWorkerCount();
                // 返回null时,runWorker的while循环会结束,线程运行结束,等待GC会被回收
                return null;
            }

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

            // Are workers subject to culling?
            // 可以认为成:当前是否是核心线程(线程是否是临时线程,可以被回收)
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

			// timedOut在第二次循环时才可能为true
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
// ---------------------------- 以上代码判断线程是否可以返回null,从而结束掉runWorker的死循环 ---------------------------- 

			// 从阻塞队列中获取任务
			// 如果当前是核心线程就执行take阻塞方法,非核心线程执行poll方法,是为了结束掉runWorker的while循环,回收线程
			// 如果核心线程也可以过期结束掉,也执行poll方法
            try {
                Runnable r = timed ?
                	// 在时间内获取任务,获取不到返回null
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    // 阻塞方法,一直获取任务
                    workQueue.take();
                // 获取到任务就返回
                if (r != null)
                    return r;
                // 获取不到,超时了
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

总结

待总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值