唠一唠Java线程池

第1章:引言

大家好,我是小黑,咱们今天来聊聊Java线程池,如果没有线程池,每个线程都需要手动创建和销毁线程,那将是多么低效和耗资源啊!

线程池的核心作用就是复用已创建的线程,减少系统开销,提高响应速度。咱们在开发高并发应用时,经常会遇到需要同时执行多个任务的场景,这时候线程池就闪亮登场了。它能够合理分配每个任务到线程,实现资源的最优使用。

但别小看了这个线程池,用得不好可是会出大问题的。比如,线程池大小配置不当,可能会导致系统崩溃,或者效率低下。所以,小黑今天就带大家深入浅出地探索Java线程池的奥秘,一起学习如何调优和监控它。

第2章:Java线程池概述

讲到线程池,咱们得先了解下Java里面线程池的基本构成。Java中的线程池主要依靠java.util.concurrent包里的ThreadPoolExecutor类来实现。它是一个强大的工具,可以帮助咱们有效地管理线程资源。

线程池的工作原理大概是这样的:有一个线程池管理器(ThreadPoolExecutor),负责创建和管理线程池;还有一个工作队列,用来存放待处理的任务;还有若干个工作线程,执行这些任务。

咱们先来看一段基础的线程池创建代码,小黑会一步一步解释:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService threadPool = Executors.newFixedThreadPool(5);for (int i = 1; i <= 10; i++) {final int taskId = i;threadPool.execute(() -> {System.out.println("执行任务:" + taskId + ",线程名:" + Thread.currentThread().getName());});}threadPool.shutdown(); // 关闭线程池}
}

这段代码创建了一个固定大小为5的线程池。Executors.newFixedThreadPool(5)这一行代码就完成了这个魔法。然后,咱们通过一个循环创建了10个任务,通过threadPool.execute()方法提交到线程池中执行。每个任务只是简单地打印出它的任务ID和执行它的线程名。

注意到了吗?这里咱们使用了shutdown()方法来关闭线程池。这是因为线程池用完之后,如果不关闭,那么它里面的线程会一直处于等待状态,这样会导致资源浪费。

第3章:线程池的核心参数解析

1. ThreadPoolExecutor的关键参数

当咱们创建一个线程池的时候,通常会遇到几个关键的参数,它们决定了线程池的行为和性能:

  • corePoolSize(核心线程数): 这个参数表示线程池中常驻的线程数量。即使线程空闲,线程池也不会释放这些线程。
  • maximumPoolSize(最大线程数): 线程池能容纳的最大线程数。当工作队列满了之后,线程池会创建新线程,直到达到这个上限。
  • keepAliveTime(线程保持活动时间): 当线程数超过核心线程数时,这是超出部分线程在空闲时的存活时间。
  • unit(时间单位): keepAliveTime的时间单位。
  • workQueue(工作队列): 存放待处理任务的队列。它通常是一个BlockingQueue的实现类。
  • threadFactory(线程工厂): 用于创建新线程的工厂。
  • handler(拒绝策略): 当线程池和工作队列都满了,如何处理新提交的任务。
2. 参数设置实例

来看一下如何在实际代码中设置这些参数:

import java.util.concurrent.*;public class ThreadPoolParameterDemo {public static void main(String[] args) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, // 核心线程数:510, // 最大线程数:101, // 空闲线程存活时间:1分钟TimeUnit.MINUTES, // 时间单位:分钟new LinkedBlockingQueue<>(10), // 工作队列大小:10Executors.defaultThreadFactory(), // 默认线程工厂new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略:直接抛出异常// 使用线程池执行任务的代码...threadPool.shutdown();}
}

这段代码创建了一个自定义的线程池。核心线程数设置为5,最大线程数是10,如果线程池中线程数量超过核心线程数,多余的线程空闲1分钟后会被回收。工作队列的容量是10,超过这个数目的任务会导致线程池增加线程,直到达到最大线程数。如果线程池和队列都满了,新提交的任务将会触发拒绝策略,在这个例子中是直接抛出异常。

3. 参数调整的影响

调整这些参数会对线程池的性能产生显著影响。例如,如果corePoolSizemaximumPoolSize设置得过大,可能会导致线程数量过多,消耗大量系统资源,甚至引发内存溢出。反之,如果设置得过小,可能无法充分利用系统资源,降低任务处理速度。

同样,keepAliveTime和工作队列的大小也需要根据具体的场景来调整。一个合理的设置可以让线程池既不浪费资源,又能高效地处理任务。

第4章:线程池调优策略

调优的关键点
  1. 了解应用的需求:是CPU密集型还是IO密集型?任务是长期运行还是短暂的?
  2. 合理设置核心和最大线程数:根据任务类型和数量调整这两个参数。
  3. 选择适合的工作队列:根据任务处理速度和队列大小合理选择。
  4. 合理配置线程存活时间:调整keepAliveTime以优化资源使用。
  5. 监控线程池的状态:通过日志或者监控工具,持续观察线程池的运行状况。
调优实例

假设小黑正在开发一个Web服务,这个服务主要处理一些短暂的HTTP请求。大部分情况下,这些请求都是IO密集型的,也就是说,线程大部分时间都在等待网络传输。那么,咱们应该怎么调整线程池的参数呢?

来看一下代码示例:

import java.util.concurrent.*;public class WebServiceThreadPool {public static void main(String[] args) {// IO密集型任务,可以适当增加最大线程数int corePoolSize = Runtime.getRuntime().availableProcessors(); // 核心线程数设置为CPU核心数int maximumPoolSize = corePoolSize * 2; // 最大线程数设置为核心线程数的两倍ThreadPoolExecutor webServiceThreadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,60L, TimeUnit.SECONDS, // 空闲线程存活时间:60秒new SynchronousQueue<>(), // 适合短任务的队列Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略:由调用线程处理该任务// 使用线程池处理任务的代码...webServiceThreadPool.shutdown();}
}

在这个例子中,核心线程数设置为CPU的核心数,因为IO密集型任务不会一直占用CPU。最大线程数是核心线程数的两倍,可以在高峰时分担更多任务。由于任务短暂,使用SynchronousQueue作为工作队列,这样一旦有任务就立即执行。线程的存活时间设置为60秒,避免频繁地创建和销毁线程。

调优是个细活儿,需要根据实际情况来。比如,如果是CPU密集型任务,最大线程数就不宜设置太高。而且,调优不是一劳永逸的,随着应用的发展,可能需要不断调整。

调优线程池是个技术活,也是个经验活。需要咱们不断实践、观察和调整。记得,持续监控线程池的状态是非常重要的。

第5章:线程池监控的必要性和方法

为什么需要监控线程池
  1. 及时发现问题:通过监控,可以及时发现线程池的性能瓶颈,比如线程饥饿、任务拥堵等。
  2. 调优依据:监控数据可以为线程池的调优提供重要依据,帮助咱们更好地理解线程池的行为。
  3. 预防系统崩溃:适时的监控可以防止因线程池配置不当导致的系统崩溃。
监控线程池的关键指标
  • 线程数量:包括核心线程数、活跃线程数、最大线程数。
  • 任务队列长度:了解队列中等待执行的任务数量。
  • 任务完成数:监控已经完成的任务数量,了解线程池的工作量。
  • 拒绝任务数:被拒绝的任务数量,这个很重要,反映了线程池的饱和度。
实现线程池监控的代码示例

来看一段Java代码,展示如何实现线程池的基本监控:

import java.util.concurrent.*;public class ThreadPoolMonitorDemo {public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, // 核心线程数10, // 最大线程数1, TimeUnit.SECONDS, // 线程保持活动时间new LinkedBlockingQueue<>(5)); // 工作队列// 提交一些任务到线程池for (int i = 0; i < 15; i++) {int taskId = i;threadPool.execute(() -> {try {Thread.sleep(100); // 模拟任务执行时间System.out.println("执行任务:" + taskId);} catch (InterruptedException e) {Thread.currentThread().interrupt();}});}// 定期监控线程池状态Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {System.out.println("====== 线程池状态监控 ======");System.out.println("核心线程数:" + threadPool.getCorePoolSize());System.out.println("活跃线程数:" + threadPool.getActiveCount());System.out.println("最大线程数:" + threadPool.getMaximumPoolSize());System.out.println("队列任务数:" + threadPool.getQueue().size());System.out.println("完成任务数:" + threadPool.getCompletedTaskCount());}, 0, 1, TimeUnit.SECONDS); // 每秒监控一次Thread.sleep(5000); // 模拟运行一段时间threadPool.shutdown();}
}

在这段代码中,咱们创建了一个线程池,然后提交了一些任务。随后,使用一个单线程定时调度器来每秒打印一次线程池的状态,包括核心线程数、活跃线程数、最大线程数、队列中的任务数和完成的任务数。

通过这样的监控,咱们可以实时地了解线程池的健康状况。如果发现有异常,比如活跃线程数持续很高或者队列任务数骤增,那就需要及时调整线程池的配置或优化任务处理逻辑了。

第6章:案例研究:线程池的调优与监控

案例背景

假设小黑在负责一个在线购物网站的后端服务。这个服务需要处理大量的用户请求,比如商品浏览、订单处理等。由于访问量大,对性能的要求也高,因此使用线程池来提高效率和响应速度是必要的。

初始线程池配置

一开始,线程池的配置是这样的:

  • 核心线程数:8
  • 最大线程数:50
  • 工作队列长度:100
  • 线程保持活动时间:60秒
遇到的问题

随着网站流量的增加,后端服务开始出现响应缓慢的问题。通过监控发现,在高峰时段,线程池的活跃线程数经常达到最大值,队列中等待的任务数也在不断增加。

调优过程

小黑根据这个情况,决定对线程池进行调优。调优的主要目标是提高系统的吞吐量和响应速度。调优的步骤包括:

  1. 增加核心线程数和最大线程数:考虑到服务器的硬件资源允许,小黑把核心线程数提高到16,最大线程数提高到100。
  2. 调整工作队列长度:为了减少任务等待时间,小黑把工作队列的长度减少到50。
  3. 优化线程保持活动时间:将线程的保持活动时间调整为30秒,以便在不那么繁忙时能更快地释放资源。
调优后的结果

调优后,系统的整体性能有了显著提升。活跃线程数更加平稳,队列中等待的任务数量也大幅减少。响应时间缩短,用户体验得到了改善。

代码示例

这里有一段模拟调优后线程池配置的代码:

import java.util.concurrent.*;public class OptimizedThreadPool {public static void main(String[] args) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(16, // 核心线程数:16100, // 最大线程数:10030L, TimeUnit.SECONDS, // 线程保持活动时间:30秒new LinkedBlockingQueue<>(50)); // 工作队列长度:50// 提交任务到线程池的代码...threadPool.shutdown();}
}

在这段代码中,线程池的配置更适合高并发的Web服务场景。核心线程数和最大线程数的提升,以及工作队列长度的调整,都是为了更好地适应用户请求的高峰。

第7章:总结

经过前面几章的深入探讨,咱们已经对Java线程池有了一个全面的了解。从基本概念到调优监控,小黑希望这些内容能帮助大家在实际工作中更好地使用线程池。

  1. 理解核心参数:核心线程数、最大线程数、工作队列等参数的合理配置对线程池的性能至关重要。
  2. 监控和调优:持续监控线程池的状态,并根据实际情况进行调优,是保证线程池高效运行的关键。
  3. 适应应用场景:根据具体的应用需求(如CPU密集型、IO密集型)来定制线程池。
  4. 性能优化:在高并发场景下,性能优化是提高应用性能的重要手段。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

固乔快递查询助手:批量、快速、全面的快递信息查询软件

在快递行业飞速发展的今天&#xff0c;如何高效、准确地掌握快递信息成为了很多人的需求。而固乔快递查询助手正是解决这一难题的利器。 固乔快递查询助手是一款专注于快递信息查询的软件&#xff0c;支持多家主流快递公司查询。用户只需输入单号&#xff0c;即可快速查询到实时…

对root用户的理解

1.什么是root用户&#xff1f; Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。在Linux系统中&#xff0c;拥有最大权限的账户名为&#xff1a;root&#xff08;超级管理员&#xff09; root用户拥有最大的系统操作权限&#xff0c;而普通用户在许多地方的权限是受…

75应急响应-数据库漏洞口令检索应急取证箱

必要知识点 第三方应用是选择性的安装的&#xff0c;比如mysql&#xff0c;如何做好信息收集&#xff0c;有没有爆过它的漏洞&#xff0c;和漏洞探针也是获取攻击者思路的重要操作&#xff0c;除去本身漏洞外&#xff0c;提前预知或口令相关攻击也要进行筛选。 排除三方应用…

力扣刷题-二叉树-合并二叉树

617.合并二叉树&#xff08;经典&#xff09; 合并二叉树是操作两棵树的题目里面很经典的&#xff0c;如何对两棵树遍历以及处理&#xff1f; 给定两个二叉树&#xff0c;想象当你将它们中的一个覆盖到另一个上时&#xff0c;两个二叉树的一些节点便会重叠。 你需要将他们合并…

LabVIEW在微生物检测中的应用

随着对食品安全关注的增加&#xff0c;食品检测的准确性变得越来越重要。其中&#xff0c;微生物计数作为食品合格的关键指标&#xff0c;对其检测技术的准确性和实时性要求极高。传统的微生物检测面临着菌落识别困难、设备实时性差和自动化程度不高等问题&#xff0c;尤其在疫…

华清远见作业第二十五天——IO(第八天)

思维导图&#xff1a; 使用信号灯集完成三个进程的同步&#xff0c;A进程输出字符A&#xff0c;B进程输出字符B&#xff0c;C进程输出字符C&#xff0c;要求输出结果为ABCABCABCABCABC 代码&#xff1a; #include<stdio.h> #include<string.h> #include<stdli…

基于 IP 多播的网络会议程序(2024)

1.题目描述 局域网 IP 多播程序&#xff0c;设计一个图形界面的网络会议程序&#xff08;实现文本多播方式即可&#xff09;。 2.演示Demo 3.参考代码 广播发送代码 //服务端 #include <winsock2.h> #include <iostream> #include <list>#pragma comment(l…

test fuzz-05-模糊测试 kelinci AFL-based fuzzing for Java

拓展阅读 开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) 开源 Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) test fuzz-01-模糊测试&#xff08;Fuzz Testing&#xff09; test fuzz-…

YOLOv8-Seg改进:轻量化改进 | 华为Ghostnetv2,端侧小模型性能新SOTA | NeurIPS22 Spotlight

🚀🚀🚀本文改进:GhostNetV2 是 GhostNet 的增强版本,GhostBottleneckV2与YOLOV8建立轻量C2f_GhostBottleneckV2 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1)手把手教你如何训练YOLOv8-seg…

微信小程序使用mqtt开发可以,真机不行

以下可以解决我的问题&#xff0c;请一步一步跟着做&#xff0c;有可能版本不一样就失败了 一、下载mqtt.js 前往蓝奏云 https://wwue.lanzouo.com/iQPdc1k50hpe 下载好后将.txt改为.js 然后放入项目里 二、连接mqtt const mqtt require(../../utils/mqtt.min); let cli…

Windows BAT脚本 | 定时关机程序

使用说明&#xff1a;输入数字&#xff0c;实现一定时间后自动关机。 单位小时&#xff0c;用后缀 h 或 H。示例 1h 单位分钟&#xff0c;用后缀 m 或 M 或 min。示例 30min 单位秒。用后缀 s 或不用后缀。示例 100s 源码 及 配置方法 桌面新建文本文件&#xff0c;输入下面…

WPF自定义漂亮顶部工具栏 WPF自定义精致最大化关闭工具栏 wpf导航栏自定义 WPF快速开发工具栏

在WPF应用程序开发中&#xff0c;自定义一个漂亮的顶部工具栏具有多重关键作用&#xff0c;它不仅增强了用户体验&#xff0c;还提升了整体应用的专业性和易用性。以下是对这一功能的详细介绍&#xff1a; 首先&#xff0c;自定义顶部工具栏是用户界面设计的重要组成部分&…

excel中解决多行文本自动调整行高后打印预览还是显示不全情况

注意&#xff1a;此方法对于多行合并后单元格行高调整不适用&#xff0c;需要手动调整&#xff0c;如大家有简便方法&#xff0c;欢迎评论。 一、调整表格为自动调整行高 1&#xff09;点击此处全选表格 2&#xff09;在第一行序号单元格的下端&#xff0c;鼠标成黑十字时&am…

图片纹理贴图

/* * 当需要给图形赋予真实颜色的时候&#xff0c;不太可能为没一个顶点指定一个颜色&#xff0c;通常会采用纹理贴图 * 每个顶点关联一个纹理坐标 (Texture Coordinate) 其它片段上进行片段插值 * */#include <iostream> #define STBI_NO_SIMD #define STB_IMAGE_IMPLE…

【Week-P4】CNN猴痘病识别

文章目录 一、环境配置二、准备数据三、搭建网络结构四、开始训练五、查看训练结果六、总结2.3 ⭐torch.utils.data.DataLoader()参数详解6.1 print()常用的三种输出格式6.2 修改网络结构&#xff0c;观察训练结果6.2.1 增加pool2、conv6、bn6&#xff0c;test_accuracy82.5%6.…

航天航空线束工艺3D虚拟展馆支持多人异地参观漫游

为了满足汽车线束企业员工工作需要&#xff0c;让新老员工了解到更先进、规范的线束工艺设计技术&#xff0c;华锐视点基于VR虚拟仿真、web3d开发和图形图像技术制作了一款汽车线束工艺设计VR虚拟仿真模拟展示系统。 汽车线束工艺设计VR虚拟仿真模拟展示系统共分为pc电脑端和VR…

时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解

时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 【原创】CPO-VMD【24年新算法…

Element+vue3.0 tabel合并单元格span-method

Elementvue3.0 tabel合并单元格 span-method :span-method"objectSpanMethod"详解&#xff1a; 在 objectSpanMethod 方法中&#xff0c;rowspan 和 colspan 的值通常用来定义单元格的行跨度和列跨度。 一般来说&#xff0c;rowspan 和 colspan 的值应该是大于等于…

zabbix监控windows主机

下载安装zabbix agent安装包 Zabbix官网下载地址: https://www.zabbix.com/cn/download_agents?version5.0LTS&release5.0.40&osWindows&os_versionAny&hardwareamd64&encryptionOpenSSL&packagingMSI&show_legacy0 这里使用zabbix agent2 安装 …

qml实现动态轮播图

一、效果展示 二、源码分享 DynamicCarousel.qmlimport QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.ShapesItem {id:selfsignal clearError(string numberStr)PathView{id:pathViewanchors.fill: parentfocus: trueclip: truemodel:listModeldele…