并发编程之线程池源码解读

线程池简介

使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
jdk1.5后新增Executors和ThreadPoolExecutor类,是Java提供的用于管理线程池的类。

三种常见的线程池详解

创建线程池

		//可缓存线程池
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        //可重用固定个数的线程池
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
        //单线程化的线程池
        ExecutorService newSingleThreadPool = Executors.newSingleThreadExecutor();

查看底层调用

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
                                      
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
                                      
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));

可以看出,这3中线程池底层最终都调用了相同的构造方法

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

首先我们弄清楚这些参数的含义:
int corePoolSize:核心线程数
int maximumPoolSize:最大线程数
long keepAliveTime:空闲线程存活时间
TimeUnit unit:存活时间单位
BlockingQueue workQueue:工作队列
ThreadFactory threadFactory:创建一个新线程时使用的工厂
RejectedExecutionHandler handler:拒绝策略

newCachedThreadPool意思构造一个最大线程数无限大的线程池,有新任务过来无空闲线程则新增线程。
newFixedThreadPool意思构造一个核心线程数和最大线程数相同、工作队列无限大的线程池,有新任务来先交给核心线程,核心线程都繁忙则全部放入队列。
newSingleThreadExecutor意思构造一个核心线程数和最大线程数都为1、工作队列无限大的线程池,有新任务来一般都放入队列中,线程一个个执行任务。

从这些参数可以看出,这3种Executors类提供的线程池都存在风险。阿里巴巴java开发手册中明确规定,不允许使用Executors类生成线程池,而是按照业务需要使用ThreadPoolExecutor类自定义参数生成线程池。
为什么呢?首先看newCachedThreadPool创建的线程,任务量大时会无限创建线程,可能CPU消耗很大或JVM最大线程数异常到时OOM。newFixedThreadPool和newSingleThreadExecutor创建的线程,任务量大时会将全部任务放入队列,导致OOM。

线程池提交、执行任务顺序

提交任务顺序

在这里插入图片描述

执行任务顺序

在这里插入图片描述

线程池源码

线程池提交任务分为submit和execute方法,submit中调用了execute方法,直接上execute代码。

public void execute(Runnable command) {
		//判断任务为空扔空指针异常
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //1.判断工作线程数小于核心线程数,直接addWorker
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //2.判断线程状态为running且放入工作队列成功
        //workQueue.offer()成功返回true
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //再次检验线程池状态,不为running则从工作队列移除,执行拒绝策略
            //可能期间执行shutdownNow操作,故需要再次检验线程池状态
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //判断无线程工作,则执行队列的线程任务
            //注意此处addWorker的Runnable为null,因为已放入阻塞队列中
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //3.最后尝试加入到工作线程,不成功则执行拒绝策略
        //此处添加到非核心线程的工作线程(最大线程数量-核心线程数量)
        else if (!addWorker(command, false))
            reject(command);
    }

提交任务逻辑:
1、提交任务先交给核心线程处理
2、其次放入工作队列
3、然后交给非核心线程处理
4、最后如果非核心线程也满,则执行拒接策略(默认抛异常)

继续上addWorker源码

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            //校验线程状态和工作队列为空
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
            //自旋+CAS增加工作线程数
            for (;;) {
                int wc = workerCountOf(c);
                //判断工作线程有无超出
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //CAS增加工作线程数,成功跳出自旋
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get(); 
                //线程状态错误继续自旋
                if (runStateOf(c) != rs)
                    continue retry;
            }
        }
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
            	//加可重入锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                	//加入workers,成功执行t.start()
                	//t为Worker的thread属性,t.start()则启动线程,执行run()
                	//public void run() {runWorker(this);}将执行runWorker()
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) 
                            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;
    }

最后扒一扒runWorker源码,就大功告成

	final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock();
        boolean completedAbruptly = true;
        try {
        	//此处是重点
        	//1.判断task不为空则执行task,意味先执行核心和非核心线程池中的task
        	//2.两者都没有task ,则取出工作队列中task执行
            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);
        }
    }

执行任务逻辑:
1、先执行核心线程和非核心线程中的任务
2、其次执行工作队列的任务

线程池超时回收

上文中说道runWorker方法中,获取task的方式有两种,w.firstTask或者从阻塞队列中获取。下面具体说说getTask方法。

	private Runnable getTask() {
        boolean timedOut = false; 
        //自旋获取
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            //1、检查线程池状态为SHUTDOWN
            //2、且状态为STOP或阻塞队列为空,直接返回
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
            int wc = workerCountOf(c);
            //关键代码
            //allowCoreThreadTimeOut为核心线程为空是否可以回收标识
            //默认为false,表示不回收核心线程,可调用allowCoreThreadTimeOut()修改
            //当核心线程可回收或者工作线程大于核心线程数,表示可回收线程
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
			//特殊情况检查
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
            try {
            	//根据上面判断的timed变量,调用不同方法
            	//true调用poll 队列有值移除返回值,无值则阻塞线程
            	//若指定时间则超过时间返回null
            	//false调用take 队列有值移除返回值,无值则阻塞线程直到有值
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

总结下,allowCoreThreadTimeOut不做修改时都为false,则只有工作线程大于核心线程数时,若在超时时间内未取到值则方法返回null,会跳出runWorker方法中while循环,执行finally中的processWorkerExit方法,大体意思为workers.remove(w),移除work。

到此线程池的工作核心流程包括创建、执行、超时销毁都一清二楚了,多谢大家观看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值