Java线程池源码及原理

编程之家收集整理的这篇文章主要介绍了Java线程池源码及原理编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

搜索热词

1 说明

下面如果有贴出源码,对应的源码是JDK8
主要的源码类
java.util.concurrent.ThreadPoolExecutor、
java.util.concurrent.ThreadPoolExecutor.Worker
java.util.concurrent.AbstractExecutorService

1.1类继承图

2 线程池的状态

3 源码分析

3.1完整的线程池构造方法

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

3.2 ctl

内部有重要的成员变量ctl,类型是AtomicInteger,低29位表示线程池中线程数,通过高3位表示线程池的运行状态
COUNT_BITS的值是29
1、RUNNING:-1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务;
2、SHUTDOWN: 0 << COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务;
3、STOP : 1 << COUNT_BITS,即高3位为001;
4、TIDYING : 2 << COUNT_BITS,即高3位为010,所有的任务都已经终止;
5、TERMINATED: 3 << COUNT_BITS,即高3位为011,terminated()方法已经执行完成

3.3 任务的执行

execute --> addWorker --> Thread.start --> (Thread.run) --> runTask --> getTask

3.3.1 execute(Runnable command)

大致分三个步骤
1、当前运行的线程数量是否小于corePoolSize,直接尝试addWorker()
2、往阻塞队列里面放入Runnable任务
3、如果队列已经满了,直接尝试addWorker()

3.3.2 addWorker(Runnable firstTask,boolean core)

1、前置判断线程池的状态
2、通过CAS操作让ctl加1,表示运行线程数增加1个
3、构造一个Worker w,这里要特别注意构造方法里面的这行代码,this.thread = getThreadFactory().newThread(this),可以看到构造方法内,有一个Thread对象,其使用了ThreadFactory构造了一个新的线程,并且线程的runable是worker本身。
4、执行w.thread.start(),也就是说,当该线程被运行时,Worker中的run方法会被执行

3.3.3 runWorker(Worker w)

通过循环调用getTask()获取要执行的任务task
beforeExecute
task.run()
afterExecute

3.3.4 getTask()

直接贴源码了

private Runnable getTask() {
    boolean timedOut = false; // 是否最后的 poll() 超时了?
    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);
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;	// worker是否需要被淘汰

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 这里会让线程的数量记录减,后面的return null,会导致runWorker没有获取到数据而让run()方法走到尽头,最终当前线程结束
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // 如果需要回收一部分线程,那么超时时间keepAliveTime后拿不到就数据就继续循环调用,就可以在下一次循环的时候进行线程结束回收了;否则一直阻塞下去
            Runnable r = timed ?
                workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

4 任务执行,带返回值的

直接贴源码了

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task,null);
    execute(ftask);
    return ftask;
}

代码比较简单,把任务封装成一个既实现Runnable,也实现Future的接口,这个时候就可以调用execute()进行实现了

5 参考资料

https://blog.csdn.net/programmer_at/article/details/79799267
https://blog.csdn.net/liuzhixiong_521/article/details/87856121

总结

以上是编程之家为你收集整理的Java线程池源码及原理全部内容,希望文章能够帮你解决Java线程池源码及原理所遇到的程序开发问题。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您喜欢寻找一群志同道合、互帮互助的学习伙伴,可以点击下方链接加入:
编程之家官方1群:1065694478(已满)
编程之家官方2群:163560250(已满)
编程之家官方3群:312128206

相关文章

猜你在找的Java相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程:是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的 资源。 虽然系统是把资源
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、对象与内存分析5、封装性6、构造方法7、this关键字8、值传递与引用
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域正常运行的情况,称之为异常。 二、异常体系 Java把异常当作对象来处理,并定义一个基类java.
//Map的四种遍历方法 //Map不能直接遍历 ,只能通过遍历Key与Value间接遍历 public static void main(String[] args) { Map&lt;String
一,抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常。下面它们之间的异同。 (1)、系统自动抛异常 1.当程序语句出现一些逻辑错误、主义错误或类型转换错误时,系统会自动抛出
Jdk 频繁更新,新特性了解吗?每次更新都注重提高生产效率,提高 JVM 性能,推行模块化等,让开发者可以更多的专注于业务本身,而不是浪费过多的时间在语言特性上。Java 语言的更新要在语言的严谨性和
Java 12 早在 2019 年 3 月 19 日发布,这些新特性你知道吗