10 分钟学会使用 Java 多线程

大家好,我是伍六七。

今天阿七来聊聊 Java 程序员们面试、工作中经常会碰到的线程池。它的概念、原理、使用以及可能会碰到的一个坑。

一、Java 线程池基本概念

1、线程池的 7 个核心参数

这是 Java 初中级程序员们面试必问的面试题了,我们来看:

  • corePoolSize(核心线程数)

corePoolSize 是线程池中保持活动状态的最小线程数。
即使线程是空闲的,它们也会一直保持在池中。
当有新任务提交时,线程池会优先创建核心线程来处理任务。

  • maximumPoolSize(最大线程数)

maximumPoolSize 是线程池中允许的最大线程数。
如果任务数超过了核心线程数,且任务队列已满,线程池会创建新的线程,但不会超过最大线程数。

  • keepAliveTime(线程空闲时间)

keepAliveTime 是非核心线程在空闲时可以存活的时间。
当线程空闲时间超过 keepAliveTime,多余的非核心线程将被终止,以减少资源消耗。

这个参数配合 TimeUnit 来定义时间单位。

  • unit(时间单位):

unit 是与 keepAliveTime 一起使用的时间单位。
它表示 keepAliveTime 的时间单位,可以是秒、毫秒、微秒等。

  • workQueue(任务队列):
    workQueue 是一个阻塞队列,用于存储等待执行的任务。
    当任务数超过核心线程数时,多余的任务会被放入任务队列中。
    常见的队列类型包括 LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue 等。

  • threadFactory(线程工厂):

threadFactory 用于创建新线程。
可以通过自定义线程工厂来配置线程的名称、优先级、是否为守护线程等属性。

  • handler(饱和策略)

handler 是当工作队列和线程池都满了之后采取的饱和策略。
常见的饱和策略有 AbortPolicy(默认,抛出异常)、CallerRunsPolicy(由调用线程执行任务)等。

这些参数在创建线程池时进行配置,通过合理调整这些参数,可以使线程池适应不同的工作负载和性能需求。例如,通过调整核心线程数和最大线程数,可以优化线程池在不同负载下的性能表现。

2、线程池是怎么运转的?

举例来说:核心线程数量为 5 个;全部线程数量为 10 个;工作队列的长度为 5。

刚开始都是在创建新的线程,达到核心线程数量 5 个后,新的任务进来后不再创建新的线程,而是将任务加入工作队列;

任务队列到达上线 5 个后,新的任务又会创建新的普通线程,直到达到线程池最大的线程数量 10 个;

后面的任务则根据配置的饱和策略来处理。如果没有配置,使用的是默认的配置 AbortPolicy:直接抛出异常。

当当前任务小于最大线程数的时候,线程资源会保持核心线程池个数的线程,其他超过的线程资源在存活时间时间之后会被回收。

二、Future 关键字

我们在项目中会经常使用 CompletableFuture 执行异步任务。那你知道 CompletableFuture 使用的是什么线程池吗?这个线程池适合执行什么类型的任务呢?

之前阿七刚转到互联网的时候,就因为使用 CompletableFuture 不当,被领导 diss 了。

我们看看源码:

// 是否使用 useCommonPool,如果(cpu 的核数 -1)大于 1,使用 ForkJoinPool,否则,不使用线程池。private static final boolean useCommonPool =(ForkJoinPool.getCommonPoolParallelism() > 1);
/*** Default executor -- ForkJoinPool.commonPool() unless it cannot* support parallelism.*/// 使用线程池还是创建普通线程private static final Executor asyncPool = useCommonPool ?ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
/** Fallback if ForkJoinPool.commonPool() cannot support parallelism */static final class ThreadPerTaskExecutor implements Executor {public void execute(Runnable r) { new Thread(r).start(); }}

我们看到,默认情况下 CompletableFuture 会使用公共的 ForkJoinPool 线程池,这个线程池默认创建的线程数是 CPU 的核数

PS:也可以通过 JVM option:-Djava.util.concurrent.ForkJoinPool.common.parallelism 来设置 ForkJoinPool 线程池的线程数。

但是也不一定就使用 ForkJoinPool,要看(cpu 的核数 -1)是否大于 1,如果大于 1,使用过 ForkJoinPool,否则,创建普通线程执行。

cpu 核数 = Runtime.getRuntime().availableProcessors();

我们要知道 CompletableFuture 获取返回是阻塞的,那我们在执行 IO 操作的时候,如果我们直接使用默认的线程池,有很大概率是会阻塞其他操作的。

所以,我们使用 CompletableFuture 的时候,如果执行 CPU 操作,可以使用默认线程池。

但是,如果执行的是 IO 操作,比如 DB 增删改查、接口调用等,尽量使用自定义线程池。

三、自定义线程池

有些情况,我们需要做到资源隔离,比如上面使用 进行 IO 操作,我们需要自定义线程池,那我们怎么定义呢?

3.1 ThreadPoolExecutor

我们可以使用 ThreadPoolExecutor,指定核心参数进行线程吹创建。

ThreadPoolExecutor cutomerPoolExecutor = new ThreadPoolExecutor(10,10,1,TimeUnit.DAYS,new ArrayBlockingQueue<>(1000),new NamedThreadFactory("business-operation-"));

创建好之后,我们就可以往里面放任务了!我们来看个例子:
首先,创建一个任务:

// 测试任务,sleep 1s,模拟执行耗时任务
public class TestTask implements Runnable {
@Overridepublic void run() {try {Thread.sleep(1000L);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

把任务放到线程池中,直接 submit 即可。

personalPoolExecutor.submit(new TestTask());
3.2 怎么设置线程池的参数?

线程池究竟设成多大是要看你给线程池处理什么样的任务,任务类型不同,线程池大小的设置方式也是不同的。

任务一般可分为:CPU 密集型、IO 密集型、混合型,对于不同类型的任务需要分配不同大小的线程池。

  • CPU 密集型任务

尽量使用较小的线程池,一般为 CPU 核心数 +1。
因为 CPU 密集型任务使得 CPU 使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。

  • IO 密集型任务

可以使用稍大的线程池,一般为 2*CPU 核心数。
IO 密集型任务 CPU 使用率并不高,因此可以让 CPU 在等待 IO 的时候去处理别的任务,充分利用 CPU 时间。

  • 混合型任务

最佳线程数 =CPU 核数 * [ 1 +(I/O 耗时 / CPU 耗时)]
可以将任务分成 IO 密集型和 CPU 密集型任务,然后分别用不同的线程池去处理。

只要分完之后两个任务的执行时间相差不大,那么就会比串行执行来的高效。

因为如果划分之后两个任务执行时间相差甚远,那么先执行完的任务就要等后执行完的任务,最终的时间仍然取决于后执行完的任务,而且还要加上任务拆分与合并的开销,得不偿失。

你学会了嘛?学会了点个赞再走~


关注我,送你全套我整理的 Java 岗位面试资料。这是我自己之前整理的面试题,靠着这份面试题,我从 30 人的小公司,进了 2000 人+的央企子公司,之后又进了互联网大厂。

一份让我进大厂&央企的面试题

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

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

相关文章

关于start-burp抓包夜神-系统证书导入

1、开启开发中模式 2、开启USB调试 3、开启端口监听并下载start-burp证书 4、证书在线格式转换 根据该网站【在线DER格式转pem CER格式转pem CRT格式转PEM证书格式--查错网】也可以搜索其它在线转换网站进行操作 新建一个文本文件重名为【9a5ba575.0】&#xff0c;将转换的内…

elemetui 解决同个页面,同时使用多个el-table表格组件导致的数据错乱

1、背景 在一个页面中&#xff0c;使用了饿了么框架的3个el-table表格&#xff0c;3个表格平级&#xff0c;只不过是根据条件判断渲染哪个表格。本来以为使用v-if就可以隔离&#xff0c;没想到还是出现了问题&#xff0c;因为3个表格中有几列绑定的字段一模一样&#xff0c;导…

Qt高级--(1)自定义导航栏

好久没有水博客&#xff0c;参考别人的写一个自定义的导航栏吧。用处挺多的&#xff0c;可以用来切换到不同的信息显示界面。 功能点 1.默认情况下&#xff0c;文字居中显示&#xff0c;不显示图标&#xff0c;不显示三角。 2.可设置文字左侧、顶部、右侧、底部边距&#xff…

2023项目总结,感悟、矛盾与规划

背景 本人自2020年加入某创新中心&#xff0c;已经三年多了&#xff0c;只能说是日月如梭、白驹过隙。家里小孩22年出生&#xff0c;现在也2岁了。房贷、户口等比较重要的几件事竟然在不知不觉中完成了&#xff0c;今天也是有时间把相关的项目做个总结。 项目总结 1、主要科研…

PHP7使用C++扩展开发

Windows 使用【php-sdk-binary-tools】工具在windows下编译dll扩展。 php-sdk-binary-tools&#xff1a;GitHub - microsoft/php-sdk-binary-tools: Tool kit for building PHP under Windows 编译过程&#xff1a;php mb扩展 windows7,php7.4自定义扩展的编写Windows篇-CSD…

20. 深度学习 - 多层神经网络

Hi&#xff0c;你好。我是茶桁。 之前两节课的内容&#xff0c;我们讲了一下相关性、显著特征、机器学习是什么&#xff0c;KNN模型以及随机迭代的方式取获取K和B&#xff0c;然后定义了一个损失函数&#xff08;loss函数&#xff09;&#xff0c;然后我们进行梯度下降。 可以…

屏幕截图软件 Snagit mac中文版软件特点

Snagit mac是一款屏幕截图和视频录制软件&#xff0c;它可以帮助用户快速捕捉屏幕上的任何内容&#xff0c;并将其编辑、标注和共享。 Snagit mac软件特点 多种截图模式&#xff1a;支持全屏截图、窗口截图、区域截图、延时截图等多种截图模式&#xff0c;满足不同用户的需求。…

python用pychart库,实现将经纬度信息在地图上显示

python使用pyecharts对给到的经纬度数据进行位置标注&#xff0c;下面是批量更新。给入数据&#xff0c;将地图生成。实验数据在下面附件。 from pyecharts import options as opts from pyecharts.charts import Geo import osfolder_path F:\\GPS file_names os.listdir(f…

数据结构和算法八股与手撕

数据结构和算法八股文 第一章 数据结构 1.1 常见结构 见http://t.csdnimg.cn/gmc3U 1.2 二叉树重点 1.2.1 各种树的定义 满二叉树&#xff1a;只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上 完全二叉树&#xff1a;除了最底层节点可能没填满外&…

【数据结构】经典单链表OJ题!!

学习完单链表&#xff0c;习题就成了最好的巩固方式 目录 1.链表分割:思路&#xff1a;代码实现&#xff1a; 2.随机链表的复制:思路1&#xff1a;代码实现&#xff1a;思路2&#xff1a;代码实现&#xff1a; 3.环形链表:3.1环形链表1:思路&#xff1a;代码实现&#xff1a; 3…

云原生之使用Docker部署home-page个人导航页

云原生之使用Docker部署home-page个人导航页 一、home-page个人导航页介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载home-page镜像五、部署home-page导航页5.1 创建挂…

153. 寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值 已知一个长度为 n 的数组&#xff0c;预先按照升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到&#xff1a; 若旋转 4 次&#xff0c;则可以得到 [4,…

ChatGPT 宕机?OpenAI 将中断归咎于 DDoS 攻击

您的 ChatGPT 已关闭吗&#xff1f;您是否遇到 ChatGPT 问题&#xff0c;例如连接问题或遇到“长响应时出现网络错误”&#xff1f;– ChatGPT 遭受了一系列 DDoS 攻击&#xff0c;显然是由匿名苏丹组织策划的。 OpenAI 的 ChatGPT 是一款流行的人工智能聊天机器人&#xff0c;…

Shiro快速入门之三

一、前言 接Shiro快速入门之二&#xff0c;上篇侧重于介绍认证&#xff0c;这篇介绍一下Shiro的授权&#xff0c;先初始化5张表的数据。 注&#xff1a;创建三条权限记录&#xff0c;一个admin角色分配查询和添加用户权限&#xff0c;一个账户qingcai18036授予管理员角色。 二…

OpenMMlab导出yolov3模型并用onnxruntime和tensorrt推理

导出onnx文件 直接使用脚本 import torch from mmdet.apis import init_detector, inference_detectorconfig_file ./configs/yolo/yolov3_mobilenetv2_8xb24-ms-416-300e_coco.py checkpoint_file yolov3_mobilenetv2_mstrain-416_300e_coco_20210718_010823-f68a07b3.pth…

股市助手:实时股市快讯,真人语音播报,助您第一时间获取最新资讯(自己写的分享给需要的人)

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 使用环境 &#x1f3e1;&#x1f4d2; 使用方法 &#x1f4d2;&#x1f4dd; 软件设置&#x1f4dd; 软件运行 &#x1f4d6; 介绍 &#x1f4d6; 给大家分享一款自己写的软件《股市助手》&#xff0c;老规矩&#xff…

发现一款好用的制作企业杂志网站/强推

除了展示企业的信息&#xff0c;企业杂志还可以成为员工展示自我、表达情感的电子书。你可以鼓励员工分享他们的故事、他们的想法、他们的创新。这样&#xff0c;企业杂志就成为了一个充满活力和创新的空间。 那么如何制作一本企业杂志呢&#xff1f;给大家推荐一款实用的网站&…

VulnHub Prime_Series_Level-1

一、信息收集 1.nmap扫描 ┌──(root&#x1f480;kali)-[~/桌面] └─# arp-scan -l┌──(root&#x1f480;kali)-[~/桌面] └─# nmap -sS -A -p- 192.168.103.202发现开放了22和80端口 2.web页面 打开80端口的web页面&#xff0c;是一张静态的图片&#xff0c;没什么价…

SQL练习01

1.游戏玩法分析 SQL Create table If Not Exists Activity (player_id int, device_id int, event_date date, games_played int); Truncate table Activity; insert into Activity (player_id, device_id, event_date, games_played) values (1, 2, 2016-03-01, 5); insert …

虚拟局域网

虚拟局域网(VLAN) VLAN建立于交换技术的基础之上 广播域(broadcast domain)&#xff1a;其中任何一台设备发出的广播通信都能被该部分网络中的所有其他设备所接收&#xff0c;这部分网络就叫广播域利用以太网交换机可以很方便地实现虚拟局域网VLAN(Virtual LAN)对于一个主机和…