返回顶部
首页 > 资讯 > 后端开发 > Python >Java线程池复用线程的秘密你知道吗
  • 235
分享到

Java线程池复用线程的秘密你知道吗

2024-04-02 19:04:59 235人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录前言源码探究execute方法addWorker方法Worker类实现了Runnable接口重要属性构造方法run方法执行流程总结前言 我们都知道线程池可以帮我们管理线程,重复利

前言

我们都知道线程池可以帮我们管理线程,重复利用线程执行不同的任务。正常情况下,我们创建的线程执行完任务后就会自行销毁,那么线程池是如何做到复用线程的呢?

源码探究

我们从线程池ThreadPoolExecutor源码入手,一探究竟。为了突出重点,以下的方法源码过滤了部分无关代码,以求逻辑清晰。

execute方法

那就从线程池执行的execute方法入手吧!来看一下方法的源码

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();        
        int c = ctl.get();
        //1.小于核心线程数时,创建线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //2.达到核心线程数,不超过队列界限时,添加到队列
        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);
        }
        //3.队列已满,不超过最大线程数时,创建线程
        else if (!addWorker(command, false))
        //4.达到最大线程数时,执行拒绝策略
            reject(command);
    }

线程池执行的4个步骤相信大家已经有所了解,这里我们只看添加线程的方法addWorker()

addWorker方法

private boolean addWorker(Runnable firstTask, boolean core) {
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//1.创建Worker,传入任务
            w = new Worker(firstTask);
            //2.取出执行任务的线程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {                    
                    int c = ctl.get();
                    if (isRunning(c) ||
                        (runStateLessThan(c, STOP) && firstTask == null)) {
                        if (t.getState() != Thread.State.NEW)
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        workerAdded = true;
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//3.执行线程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

参数解释:

core:true表示添加的是核心线程,false表示添加的非核心线程

这里大家只需要关心这3行加注释的代码就可以了

就是Worker管理了创建的线程和这个线程执行的第一个任务,并且在addWorker方法中调用线程的start方法,开启线程执行了任务。下面我们看看Worker这个类

Worker类

实现了Runnable接口

Worker 是线程池ThreadPoolExecutor的内部类,实现了Runnable接口

private final class Worker    extends AbstractQueuedSynchronizer    implements Runnable

重要属性

他有两个核心关键的属性,即封装了线程池的线程和要执行的任务,达到了线程和任务解耦的目的。

final Thread thread;
Runnable firstTask;

构造方法

addWorker方法会执行创建一个worker

w = new Worker(firstTask);

看一下Worker的构造方法

Worker(Runnable firstTask) {
	this.firstTask = firstTask;    		
	this.thread = getThreadFactory().newThread(this);
}

可以看到 新创建的Worker本身也是一个Runnable,他的thread传的runnable任务就是worker本身

在addWorker方法,最终会取到worker的thread属性,然后启动这个thread

w = new Worker(firstTask);
final Thread t = w.thread;
... ...
t.start();

run方法

刚才介绍过,worker的thread的runnable参数传的就是worker本身,就是调的worker的run方法,现在我们来看最核心的worker的run方法

public void run() { 
	runWorker(this);
}

调的是ThreadPoolExecutor的runWorker方法

final void runWorker(Worker w) {
    Runnable task = w.firstTask;
    w.firstTask = null;
    try { 
        while (task != null || (task = getTask()) != null) 
        {           
            ...           
            task.run();
            ...

可以看到runWorker核心是一个while循环,执行了第一个task之后,就不停的从队列中取任务,直到没有任务了才会执行完,销毁线程

执行流程

execute方法调用addWorker方法,并且执行worker.thread.start()开启线程

​ ——》worker.thread 执行worker本身的run方法(worker实现了Runnable接口)

​ ——》执行ThreadPoolExecutor的runWorker方法,是个while循环,执行完worker本身的第一个任务之后,就不停从队列取任务,直到没有任务,执行完,退出循环,销毁

总结

线程池将线程和任务进行解耦,线程是线程,任务是任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。

在线程池中,同一个线程可以从阻塞队列中不断获取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个“循环任务”,在这个“循环任务”中不停的检查是否有任务需要被执行,如果有则直接执行,也就是调用任务中的 run 方法,将 run 方法当成一个普通的方法执行,通过这种方式将只使用固定的线程就将所有任务的 run 方法串联起来。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!             

--结束END--

本文标题: Java线程池复用线程的秘密你知道吗

本文链接: https://www.lsjlt.com/news/141547.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java线程池复用线程的秘密你知道吗
    目录前言源码探究execute方法addWorker方法Worker类实现了Runnable接口重要属性构造方法run方法执行流程总结前言 我们都知道线程池可以帮我们管理线程,重复利...
    99+
    2024-04-02
  • java多线程开启的三种方式你知道吗
    目录1、继承Thread类,新建一个当前类对象,并且运行其start()方法2、实现Runnable接口,然后新建当前类对象,接着新建Thread对象时把当前类对象传进去,最后运行T...
    99+
    2024-04-02
  • 单线程会导致死锁你知道吗
    死锁从文字理论上说明的是两个线程,可以认为是两个人A和B,A在等待B完成某件事情,B又在等待A完成某件事情。 那如果在代码中,单线程的某个函数,有没有可能导致死锁呢? 我们看下面的...
    99+
    2024-04-02
  • SpringBoot线程池和Java线程池怎么使用
    这篇文章主要介绍“SpringBoot线程池和Java线程池怎么使用”,在日常操作中,相信很多人在SpringBoot线程池和Java线程池怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringB...
    99+
    2023-07-06
  • Java Runnable和Thread实现多线程哪个更好你知道吗
    目录1.避免由于Java单继承带来的局限性2.可以实现业务执行逻辑和数据资源的分离3.可以与线程池配合使用,从而管理线程的生命周期总结实现Runnable 接口比继承Thread 类...
    99+
    2024-04-02
  • ConcurrentHashMap是如何实现线程安全的你知道吗
    目录1. 前言2. ConcurrentHashMap 是如何实现线程安全的2.1. 初始化数据结构时的线程安全2.2. put 操作时的线程安全2.3. get 操作时的线程安全2...
    99+
    2022-11-13
    ConcurrentHashMap 线程安全 ConcurrentHashMap线程安全
  • 优化 Java 线程池性能的秘诀
    线程池是 Java 中管理线程的重要组件,优化其性能至关重要。通过遵循以下秘诀,可以提高线程池效率,增强应用程序的性能。 1. 正确配置核心线程数和最大线程数 核心线程数定义了线程池始终保持的线程数量,而最大线程数限制了创建的新线程数量。...
    99+
    2024-03-13
    线程池
  • Python学习教程_Python学习路线:Python3里你不知道的秘密特性
    Python学习教程_Python学习路线:Python3里你不知道的秘密特性概述到2020年,Python2的官方维护期就要结束了,越来越多的Python项目从Python2切换到了Python3。其实在实际工作中,很多伙伴都还是在用Py...
    99+
    2023-06-02
  • Java存储在Spring容器中的秘密:你知道吗?
    在Java开发中,Spring框架被广泛应用于开发大型Web应用程序。其中,Spring容器是一个非常重要的组件,它负责管理JavaBean的生命周期和依赖注入。但是,你知道吗?Spring容器中有一些非常有用的特性,它们可以让你更好地管...
    99+
    2023-11-02
    存储 spring 容器
  • Java线程池知识点有哪些
    这篇文章将为大家详细讲解有关Java线程池知识点有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、线程数使用开发规约阿里巴巴开发手册中关于线程和线程池的使用有如下三条强制规约【强制】创建线程或线程池...
    99+
    2023-06-29
  • Java中多线程、线程同步与死锁的一些不为人知的秘密
    今天就跟大家聊聊有关Java中多线程、线程同步与死锁的一些不为人知的秘密,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1.线程同步多线程引发的安全问题一个非常经典的案例,银行取钱的问...
    99+
    2023-05-31
    java 多线程 线程同步
  • 学Java线程,你不知道什么是AQS?一文带你了解Java多线程同步的灵魂
    关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 目录 一、导读1.1 CLH锁 二、概览三、使用场景3.1...
    99+
    2023-08-17
    开发语言 面试 android 线程 java
  • Java线程池怎么用
    小编给大家分享一下Java线程池怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、什么是线程池?线程池是一种用于实现计算机程序并发执行的软件设计模式。线程池...
    99+
    2023-06-15
  • 详解Java线程池是如何重复利用空闲线程的
    在Java开发中,经常需要创建线程去执行一些任务,实现起来也非常方便,但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率...
    99+
    2024-04-02
  • 如何在Java中创建线程通信的四种方式你知道吗
    目录1.1 创建线程1.1.1 创建线程的四种方式1.1.2 Thread类与Runnable接口的比较1.1.3 Callable、Future与FutureTask1.2 线程组...
    99+
    2024-04-02
  • java怎么停止线程池中的线程
    要停止线程池中的线程,可以使用 `ExecutorService` 接口提供的 `shutdown()` 方法来停止线程池。这个方法...
    99+
    2023-08-20
    java
  • Java线程池全面知识点总结
    本篇内容介绍了“Java线程池全面知识点总结”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!原理线程池的原理非常简单,这里用处理流程来概括:线...
    99+
    2023-06-25
  • Java线程池必知必会知识点总结
    目录1、线程数使用开发规约2、 ThreadPoolExecutor源码1. 构造函数2.核心参数3.execute()方法3、线程池的工作流程4、Executors创建返回Thre...
    99+
    2024-04-02
  • java怎么使用线程池启动多线程
    在 Java 中,可以使用线程池来启动多线程。以下是使用线程池启动多线程的示例代码:首先,需要导入 `java.util.concu...
    99+
    2023-09-15
    java
  • 你知道吗?Bash编程在Java教程中的应用!
    Bash编程在Java教程中的应用 Bash是一种命令行解释器,在Linux和Unix系统中被广泛使用。它可以解释和执行Bash脚本文件,这些文件包含了一系列命令和操作,可以用于自动化和简化各种任务。Bash编程在Java教程中也有很多应用...
    99+
    2023-06-19
    教程 编程算法 bash
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作