java线程池概述

Java线程池的实现主要通过`java.util.concurrent.ThreadPoolExecutor`类来完成,它是Java并发包中的核心类之一,提供了强大的线程池管理能力。下面通过分析`ThreadPoolExecutor`的部分关键源代码来详细说明其工作原理和使用方法。

### 创建线程池

首先,我们来看如何创建一个线程池。以下是一个简单的示例,展示了如何使用`ThreadPoolExecutor`的构造函数来创建一个线程池:```java

import java.util.concurrent.*;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 核心线程数
        int corePoolSize = 5;
        // 最大线程数
        int maximumPoolSize = 10;
        // 空闲线程存活时间
        long keepAliveTime = 60L;
        // 时间单位
        TimeUnit unit = TimeUnit.SECONDS;
        // 任务队列
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
        // 线程工厂,用于创建新线程
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        // 拒绝策略
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        // 创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );
        
        // 提交任务到线程池
        for (int i = 0; i < 20; i++) {
            executor.execute(new RunnableTask());
        }
        
        // 关闭线程池
        executor.shutdown();
    }
    
    static class RunnableTask implements Runnable {
        @Override
        public void run() {
            System.out.println("Task executed by " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}


```

### `ThreadPoolExecutor`关键属性和构造函数参数

- `corePoolSize`:线程池的核心线程数,即使线程空闲,除非设置了`allowCoreThreadTimeOut`为true,否则这部分线程也会一直存活。
- `maximumPoolSize`:线程池能够容纳的最大线程数。
- `keepAliveTime`:非核心线程闲置时的超时时长,超过这个时间会终止线程。
- `unit`:用于时间量度的单位,如`TimeUnit.SECONDS`。
- `workQueue`:任务队列,用于保存等待执行的任务,常用的有`LinkedBlockingQueue`、`ArrayBlockingQueue`等。
- `threadFactory`:用于创建新线程的工厂。
- `handler`:拒绝策略,当线程池和任务队列都满时,用于处理新的任务请求,常见的有`AbortPolicy`(抛出异常)、`CallerRunsPolicy`(调用者线程执行任务)、`DiscardPolicy`(丢弃任务)、`DiscardOldestPolicy`(丢弃队列最旧的任务并尝试重新提交当前任务)。

### 核心方法

- `execute(Runnable command)`:提交一个不需要返回值的任务执行,这是线程池最核心的方法。
- `submit(Callable<T> task)`:提交一个有返回值的任务执行,并返回一个Future对象用于获取结果。
- `shutdown()`:启动有序关闭,停止接收新任务,但已提交的任务会继续执行直到完成。
- `shutdownNow()`:尝试停止所有正在执行的任务,并停止处理新任务,返回等待执行的任务列表。

### 源码解析简述

`ThreadPoolExecutor`内部维护了一个原子整数`ctl`,它用高3位表示线程池的状态(RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED),低29位表示当前活动线程数。通过`ctl`的CAS操作来管理线程池状态和线程数量,保证了线程安全。

在`execute`方法中,线程池会根据当前的线程数和任务队列情况,决定是创建新线程、加入任务队列还是拒绝任务。如果需要创建新线程,它会通过`threadFactory`创建,并将其封装成`Worker`对象,然后启动这个线程去执行任务队列中的任务。

以上是`ThreadPoolExecutor`的基础使用和部分源码原理的简要介绍,实际上线程池的实现远比此复杂,还包括了工作窃取、线程复用、线程中断、任务拒绝处理等多种高级特性。

### 线程池的工作流程

了解线程池的工作流程对于深入理解其机制非常重要。下面是`ThreadPoolExecutor`执行任务的一个简化流程:

1. **任务提交**:当通过`execute()`方法提交一个任务时,线程池会执行以下判断逻辑:
   - 如果当前运行的线程数少于核心线程数(`corePoolSize`),即使线程池中有空闲线程,也会直接创建一个新线程来执行任务。
   - 如果当前运行的线程数等于核心线程数,任务会被放入任务队列中排队等待执行。
   - 如果任务队列已满,并且当前运行的线程数小于最大线程数(`maximumPoolSize`),则会创建新的线程来执行任务。
   - 如果以上条件都不满足,即线程数达到最大并且任务队列也满了,此时会触发拒绝策略处理这个任务。

2. **线程复用**:一旦线程创建,除非线程池关闭或者线程被允许超时(通过`allowCoreThreadTimeOut(true)`配置),否则线程会一直存活,等待执行新的任务。这意味着任务执行完毕后,线程并不会立即销毁,而是进入空闲状态,等待下一个任务到来。

3. **线程回收**:对于超过核心线程数的线程(即非核心线程),在空闲时间超过`keepAliveTime`后,会自动终止。核心线程是否允许超时取决于构造函数的配置。

4. **任务队列**:线程池中的任务队列是线程池的重要组成部分,它决定了任务的排队策略。常见的队列有无界队列(如`LinkedBlockingQueue`,可能导致任务无限堆积)、有界队列(如`ArrayBlockingQueue`,限制了任务队列的大小,有助于防止资源耗尽)、同步队列(如`SynchronousQueue`,不存储任务,直接将任务交给线程执行,适合大量短任务快速处理的场景)。

5. **拒绝策略**:当线程池和任务队列都达到了它们的容量上限,新提交的任务将会由拒绝策略处理。Java提供了几种内置的拒绝策略:
   - `AbortPolicy`:默认策略,抛出`RejectedExecutionException`异常。
   - `CallerRunsPolicy`:调用者所在线程自己去执行该任务。
   - `DiscardPolicy`:直接丢弃任务,不执行也不抛出异常。
   - `DiscardOldestPolicy`:丢弃队列中最旧的任务,然后尝试重新提交被拒绝的任务。

### 扩展知识

- **线程池监控**:`ThreadPoolExecutor`提供了丰富的监控接口,如`getPoolSize()`、`getActiveCount()`、`getQueue()`等,可以帮助开发者监控线程池的运行状态。
- **自定义线程池**:虽然`Executors`类提供了便捷方法来创建不同类型的线程池,但为了更精确地控制线程池的行为,推荐直接使用`ThreadPoolExecutor`构造函数自定义线程池参数。
- **工作窃取(Work Stealing)**:Java的`ForkJoinPool`是一个特殊的线程池,实现了工作窃取算法,适用于大量相互独立的任务。在这种模型下,空闲的线程可以从其他繁忙线程的任务队列中“窃取”任务来执行,提高了多核处理器的利用率。

理解线程池的运作机制和合理配置线程池参数,对于提升程序的性能、响应时间和资源利用率至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/607251.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang——Strconv包

func ParseBool(str string) (value bool, err error) strconv包实现了基本数据类型与其字符串表示的转换&#xff0c;主要有以下常用函数&#xff1a;Atoi()&#xff0c;Itoa()&#xff0c;parse系列函数&#xff0c;format系列函数&#xff0c;append系列函数。 1.1 string与…

6份不用辞职就能赚钱的副业,上班族必看!

在这个经济浪潮中&#xff0c;生活成本的上升与工资增长的缓慢形成了鲜明对比。对于许多上班族来说&#xff0c;寻找额外收入的途径显得尤为迫切。 今天&#xff0c;就让我们一起探索那些适合在业余时间开展的副业&#xff0c;为你的财务自由之路添砖加瓦。 1. 闲鱼二手手机售卖…

SEO之高级搜索指令(三)

初创企业需要建站的朋友看这篇文章&#xff0c;谢谢支持&#xff1a; 我给不会敲代码又想搭建网站的人建议 新手上云 &#xff08;接上一篇。。。。&#xff09; 11、link: link:也是SEO 常用的指令&#xff0c;用来搜索某个url的反向链接&#xff0c;既包括内部链接&#xf…

python编程“常识”【pip安装路径、计算、pycharm中的terminal运行前面的PS修改成自己环境】

一、默认的pip install包路径&#xff1a; pip show pip 二、计算 打开cmd&#xff0c;输入&#xff1a; ipython 例如你要计算2的13次方&#xff1a; ok. 三、pycharm中的terminal运行前面的PS修改成自己环境 未修改前&#xff1a; 修改过程&#xff1a; 打开设置找到too…

渗透之sql注入---宽字节注入

宽字节注入原理&#xff1a; 宽字节注入就是在对用户输入进行处理时&#xff0c;将编码方式改变&#xff0c;当某些关键字符被过滤&#xff08;转义&#xff09;时&#xff0c;我们可以使用其他的编码在被转义的字符前面&#xff0c;这样就可以组成一个新的字符从而来实现绕过…

【备战软考(嵌入式系统设计师)】10 - 软件工程基础

这一部分的内容是概念比较多&#xff0c;不要理解&#xff0c;去感受。 涉及的知识点是嵌入式系统开发和维护的部分&#xff0c;也就是和管理相关的&#xff0c;而不是具体如何进行嵌入式系统开发的细节。 系统开发生命周期 按照顺序有下面几个阶段&#xff0c;我们主要要记…

WPF容器控件之WrapPanel、布局控件

WrapPanel: 换行panel 子元素进行换行&#xff0c;当子元素的宽度或者高度超出了父元素&#xff0c;才进行换行。高度超出父元素的高度 也会另起一列 属性 Orientation布局方式 实例 <WrapPanel Orientation"Horizontal"><Label>C# 是从 C/C 衍生出来的…

zabbix动作执行命令失效不起作用?

1. zabbix在web界面设置完主机组&#xff0c;主机&#xff0c;监控项&#xff0c;触发器&#xff0c;动作之后 监控项监控到了&#xff0c;触发器触发动作&#xff0c;但是执行的指令不起作用 流程 在zabbix-agent端将nginx服务down掉&#xff0c;zabbix会自动监控并执行重启的…

一文了解Memcache内存分配机制及stats参数

一、Memcache内存分配机制 了解memcached必须了解的三个单位&#xff1a;page、slabs、chunk。 1.1、Page Page为内存分配的最小单位,Memcached的内存分配以page为单位&#xff0c;默认情况下一个page是1M&#xff0c;可以通过-I参数在启动时指定。如果需要申请内存 时&#…

NeRF算法

目录 算法介绍 基本原理 1. 体渲染 2. 多层感知机&#xff08;MLP&#xff09; 3. 位置编码 4. 两阶段层次化体采样 实验展示 代码解析 算法介绍 NeRF&#xff08;Neural Radiance Fields&#xff09;是一种用于从2D图像中重建3D场景的神经网络模型。它通过训练一个深度…

sourceTree push失败

新电脑选择commit and push&#xff0c;报错了&#xff0c;不过commit成功&#xff0c;只不过push失败了。 原因是这个&#xff0c;PuTTYs cache and carry on connecting. 这里的ssh选择的是 PuTTY/Plink&#xff0c;本地没有这个ssh密钥&#xff0c;改换成openSSH&#xff…

SRM系统供应链库存协同提升企业服务水平

SRM系统供应链库存协同是一种以提高供应链整体效率和竞争力为目标的管理方法。它涉及到企业与供应商之间的紧密合作&#xff0c;以实现库存优化、成本降低、风险分担和灵活响应市场变化等目标。 一、SRM供应链库存协同的概念和特点 SRM供应链库存协同是指企业与供应商之间通过…

音转文工具,9.8k star! 【送源码】

我们经常会遇到将音频转为文字的情况&#xff0c;比如在开会时录音的会议纪要、上课时录下的老师讲课内容。虽然网上也有一些在线的工具可以将音频转为文字&#xff0c;但是考虑到数据安全和费用问题&#xff0c;使用起来也不是很方便。 今天了不起给大家介绍一款开源工具——…

毕业论文应该怎么写?推荐几款ai写论文工具

时间过的好快&#xff0c;马上又到了一年一度的毕业季了&#xff0c;对于即将毕业的学生来说毕业论文是一道难过的坎&#xff0c;想到自己为了毕业论文熬的夜&#xff0c;掉的头发&#xff0c;真的深有感触。 不过虽然翟博士给大家的毕业论文设了高门槛&#xff0c;但是随着时…

python之装饰器,模块和文件操作和面向对象

1.装饰器详解(重点) 1_1 装饰器 程序运行的时候的记录 -- 日志 在实际工作中&#xff0c;python这样的东西&#xff0c;是放在服务器上运行的 日志其实就是记录下来当前程序的运行&#xff0c;协助我们定位问题 确定问题的方式&#xff08;通过日志、报错信…

宏的优缺点?C++有哪些技术替代宏?(const)权限的平移、缩小

宏的优缺点&#xff1f; 优点&#xff1a; 1.增强代码的复用性。【减少冗余代码】 2.提高性能&#xff0c;提升代码运行效率。 缺点&#xff1a; 1.不方便调试宏。&#xff08;因为预编译阶段进行了替换&#xff09; 2.导致代码可读性差&#xff0c;可维护性差&#xff0…

Java线程池(更新中)

1.线程池介绍 顾名思义&#xff0c;线程池就是管理一系列线程的资源池&#xff0c;其提供了一种限制和管理线程资源的方式。每个线程池还维护一些基本统计信息&#xff0c;例如已完成任务的数量。 总结一下使用线程池的好处&#xff1a; 降低资源消耗。通过重复利用已创建的…

猎头告诉你正确的“离职流程”

往期热门文章&#xff1a; 1&#xff0c;史上最全猎头技能资料&#xff0c;独家最新放送 2&#xff0c;互联网大厂java面试题知识库&#xff08;100万字&#xff09; 3&#xff0c;一线互联网大数据面试题知识库&#xff08;100万字&#xff09; 4&#xff0c;中国猎头公司排行…

SQL优化详解

目录 插入数据 insert的优化&#xff08;少量数据&#xff09; 批量插入 手动事务提交 主键顺序插入 插入大量数据 主键优化 数据组织方式&#xff1a; 页分裂&#xff1a; 主键顺序插入的方式&#xff1a; 主键乱序插入&#xff1a; 页合并&#xff1a; 主键设计…

HTML5/CSS3粒子效果进度条 超炫酷进度条动画源码

特效介绍 之前我已经分享了几款效果很不错的CSS3进度条插件&#xff0c;比如CSS3 Loading进度条加载动画特效、CSS3 3D进度条按钮 18款精美样式。今天我再来分享一款很有特色的HTML5/CSS3进度条应用。这款进度条插件在播放进度过程中出现粒子效果&#xff0c;就像一些小颗粒从…
最新文章