【JavaEE】线程池

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期将会分享线程池知识.

目录

引入

什么是线程池

为什么使用线程池会更高效

Java标准库中的线程池

ThreadPoolExecutor

 Executors

创建线程池时,怎么设定线程数合适?

实现一个自定义的线程池

具体代码


引入

在开始,为了解决并发编程的问题,我们引入了进程. 但随着不断发展我们发现进程的创建销毁的开销会比较大,因此我们就又引入了进程.但是随着线程创建的频率提高,这样的开销又逐渐大起来了.这个时候我们就有了两种解决方法.第一种就是引入我们的纤程/携程. 纤程的本质上就是在用户态代码中调度和控制,这样就可以不让内核态来调度.这样就节省了调度的开销.纤程就是基于线程封装出来了,一般都是多个纤程对应一个线程.

第二个方法就是我们本文需要讲的线程池~

什么是线程池

在我学变成代码中,我们会经常遇到一些带有池的名词,比如: 常量池,数据库连接池,线程池等. 池的作用就是提前将对象创建好,在需要使用的时候就去池子里面拿,用完了也不要立刻销毁,而是再放回池里等待下次使用.这样就可以很好的提高效率,因为节省了创建对象和销毁对象的开销.

而线程池也是这样,它的本质也就是提前将线程在线程池中创建好,使用完后也不会立刻销毁,会返回线程池等待下一次的使用.这样也就是节省了创建和调度的开销.

为什么使用线程池会更高效

因为从线程池中拿线程是在用户态代码中调度执行的,是可控的.而直接创建线程是需要在内核态中创建,这时不可控的.因为你也不知道什么时候CPU才会给创建线程.

举个栗子:

这就像你去银行办理银行卡,它可能需要你打印身份证复印件.这时你有两个选择: 1. 直接拿着身份证去大厅的自助打印机打印. 2.把身份证交给工作人员,由她帮你打印. 要是你自己打印就是直接去中途不会干其他的事情,但是交给工作人员保不准她可能没有第一时间给你打印,而是先去干其他的事情. 这里办公区就属于内核态,大厅就属于用户态. 

Java标准库中的线程池

ThreadPoolExecutor

Java标准库中的线程池是ThreadPoolExecutor. 它有多个参数,我们需要去了解一下.我们可以去Java的官方文档里面找 ThreadPoolExecutor (Java 平台 SE 8) (oracle.com) 我们需要找到concurrent这个包.这个包里就有ThreadPoolExecutor这个类. 我们可以找到它的构造方法.

这里我们理解第4个即可,其他几个的参数第4个都包含.

int corePoolSize: 核心线程数.可以理解为公司里的正式员工.

int maximumPoolSize: 最大线程数.可以理解为公司里的临时工,公司不忙了就可以开除的那种.

long keepAliveTime: 存活时间,就是除去核心线程的其他线程的存活时间. 可以理解为当零时工闲下来多久会被开除.

TimeUnit unit: 存活时间的单位.

BlockingQueue<Runnable> workQueue: 阻塞队列,这个队列里面存放的就是线程需要执行的任务,线程会到里面去取任务.

ThreadFactory threadFactory: 线程工厂,线程池就是通过这个工厂类来创建线程. 本质上就是将创建线程对象的操作封装起来且再设置一些线程的属性.

RejectedExecutionHandler handler: 拒绝策略. 当阻塞队列满了之后,再添加新的任务进来,这个拒绝策略就会出来处理. 它提供了4个方法:

1. 直接抛出异常,新的任务和旧的任务都不执行了.

2. 新的任务由这个添加新任务的线程来执行.

3. 丢弃最旧的任务,再将这个新的任务添加进阻塞队列.

4. 丢弃这个需要添加进来的新任务,继续照常执行.

 Executors

因为这个类的参数比较多,用起来比较复杂.Java就又用一个类将它封装起来了,变成了一个比较简单的线程类Executors.它也是一个工厂类. 也是通过这个类创建好不同的线程池对象,在它的内部就已经创建好了线程池对象且设置了一些它的参数.

它有好几种创建线程池的方式:

newFixedThreadPool创建固定线程数的线程池
newCachedThreadPool创建线程数可以动态增长的线程池
newSingleThreadExecutor创建只含有单个线程的线程池
newScheduledThreadPool创建线程可以延时执行任务的线程池,类似于定时器

这里两个类我们可以看情况来使用.

创建线程池时,怎么设定线程数合适?

这里用一句话来概括就是具体问题具体分析.

我们线程执行任务分为两种: 一种为CPU密集型,一种为IO密集型.CPU密集型的线程就是使用CPU的时间比较长.而IO密集型的线程就是使用CPU时间少,大多数时间都是在IO等待中. 这里极端一点,都是CPU密集型的话线程池的线程数不能超过逻辑核心数,而都是IO密集型的话线程数就可以远远超过逻辑核心数了.

但是在我们实际开发中,一般都是CPU密集型一部分,IO密集型一部分.这种情况下我们就需要具体问题具体分析了.最好的办法就是进行性能测试,给线程池的线程数进行多组不同数目的测试,观察他们的系统资源开销和时间开销,取其中最好的即可.

实现一个自定义的线程池

这里我们实现一个简单的固定线程数的线程池.

我们需要:
1. 一个存放任务的阻塞队列

2. 一个核心方法来添加任务.

3. 用构造方法来指定线程数,创建好线程.

具体代码

class MyThreadPoolExecutor3 {//1. 存放任务的阻塞队列private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);//2. 构造方法public MyThreadPoolExecutor3(int capacity) {for(int i = 0; i <capacity; i++) {Thread t = new Thread(() -> {while(true) {Runnable runnable = null;try {runnable = queue.take();} catch (InterruptedException e) {throw new RuntimeException(e);}runnable.run();}});t.start();}}//核心方法 submit 添加方法public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}
public class ThreadDemo3 {public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor3 myThreadPoolExecutor3 = new MyThreadPoolExecutor3(4);for (int i = 0; i < 1000; i++) {int n = i;myThreadPoolExecutor3.submit(() -> {System.out.println(n + " " + Thread.currentThread().getName() + " hello");});}}}

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

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

相关文章

springcloud分布式事务

文章目录 一.为什么引入分布式事务?二.理论基础1.CAP定理2.BASE理论 三.Seata1.微服务集成Seata2.XA模式(掌握)3.AT模式(重点)4.TCC模式(重点)5.Saga模式(了解) 四.四种模式对比五.Seata高可用 一.为什么引入分布式事务? 事务的ACID原则 在大型的微服务项目中,每一个微服务都…

案例课4——智齿客服

1.公司介绍 智齿科技&#xff0c;一体化客户联络中心解决方案提供商。提供基于「客户联络中心」场景的一体化解决方案&#xff0c;包括公域私域、营销服务、软件BPO的三维一体化。 智齿科技不断整合前沿的人工智能及大数据技术&#xff0c;已构建形成呼叫中心、机器人「在线语音…

Python中函数的递归调用

函数调用自己的编程方式被称为函数的递归调用。递归通常能够将一个大型的复杂问题的递归条件&#xff0c;一层一层的回溯到终止条件&#xff0c;然后再根据终止条件的运算结果&#xff0c;一层一层的递进运算到满足全部的递归条件。它能够使用少量程序描述出解题过程中的重复运…

主机访问Android模拟器网络服务方法

0x00 背景 因为公司的一个手机app的开发需求&#xff0c;要尝试链接手机开启的web服务。于是在Android Studio的Android模拟器上尝试连接&#xff0c;发现谷歌给模拟器做了网络限制&#xff0c;不能直接连接。当然这个限制似乎从很久以前就存在了。一直没有注意到。 0x01 And…

分销电商结算设计

概述 分销电商中涉及支付与结算&#xff1b;支付职责是收钱&#xff0c;结算则是出钱给各利益方&#xff1b; 结算核心围绕业务模式涉及哪些费用&#xff0c;以及这些费用什么时候通过什么出资渠道&#xff0c;由谁给到收方利益方&#xff1b; 结算要素组成费用项结算周期出…

区块链的可拓展性研究【03】扩容整理

为什么扩容&#xff1a;在layer1上&#xff0c;交易速度慢&#xff0c;燃料价格高 扩容的目的&#xff1a;在保证去中心化和安全性的前提下&#xff0c;提升交易速度&#xff0c;更快确定交易&#xff0c;提升交易吞吐量&#xff08;提升每秒交易量&#xff09; 目前方案有&…

详解进程管理(银行家算法、死锁详解)

处理机是计算机系统的核心资源。操作系统的功能之一就是处理机管理。随着计算机的迅速发展&#xff0c;处理机管理显得更为重要&#xff0c;这主要由于计算机的速度越来越快&#xff0c;处理机的充分利用有利于系统效率的大大提高&#xff1b;处理机管理是整个操作系统的重心所…

前后端联调神器《OpenAPI-Codegen》

在后端开发完接口之后&#xff0c;前端如果再去写一遍接口来联调的话&#xff0c;会很浪费时间&#xff0c;这个时候使用OpenAPI接口文档来生成Axios接口代码的话&#xff0c;会大大提高我们的开发效率。 Axios引入 Axios是一个基于Promise的HTTP客户端&#xff0c;用于浏览器…

Go压测工具

前言 在做Go的性能分析调研的时候也使用到了一些压测方面的工具&#xff0c;go本身也给我们提供了BenchMark性能测试用例&#xff0c;可以很好的去测试我们的单个程序性能&#xff0c;比如测试某个函数&#xff0c;另外还有第三方包go-wrk也可以帮助我们做http接口的性能压测&…

C# 任务并行类库Parallel调用示例

写在前面 Task Parallel Library 是微软.NET框架基础类库&#xff08;BCL&#xff09;中的一个&#xff0c;主要目的是为了简化并行编程&#xff0c;可以实现在不同的处理器上并行处理不同任务&#xff0c;以提升运行效率。Parallel常用的方法有For/ForEach/Invoke三个静态方法…

Element-UI定制化Tree 树形控件

1.复制 说明&#xff1a;复制Tree树形控件。 <script> export default {data() {return {data: [{label: 一级 1,children: [{label: 二级 1-1,children: [{label: 三级 1-1-1}]}]}, {label: 一级 2,children: [{label: 二级 2-1,children: [{label: 三级 2-1-1}]}, {l…

Linux:进程优先级与命令行参数

目录 1.进程优先级 1.1 基本概念 1.2 查看系统进程 1.3 修改进程优先级的命令 2.进程间切换 2.1 相关概念 2.2 Linux2.6内核进程调度队列&#xff08;了解即可&#xff09; 3.命令行参数 1.进程优先级 1.1 基本概念 cpu资源分配的先后顺序&#xff0c;就是指进程的优…

【C++】在类外部定义成员函数时,不应该再次指定默认参数值

2023年12月10日&#xff0c;周日下午 错误的代码 #include<iostream>class A { public:void fun(int a10); };void A::fun(int a10) //<----在这里报错 {}int main() {} 正确的代码 代码目前有一个问题&#xff0c;主要是在类外部定义成员函数时&#xff0c;不应该…

解密QQ号——C语言

题目&#xff1a; 有一串已加密的数字“6 3 1 7 5 8 9 2 4”解密规则&#xff1a;首先将第1个数字删除&#xff0c;紧接着将第2个数字放到这串数字的末尾&#xff0c;再将第3个数字删除并将第4个数字放到这串数字的末尾&#xff0c;再将第5个数删除 代码实现&#xff1a; #inc…

利用Node.js和cpolar实现远程访问,无需公网IP和路由器设置的完美解决方案

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…

ESP32网络编程-OTA方式升级固件(基于Web浏览器)

OTA方式升级固件(基于Web浏览器) 文章目录 OTA方式升级固件(基于Web浏览器)1、ESP32的OTA介绍2、OTA升级固件方式3、软件准备4、硬件准备5、代码实现6、一种优雅方式实现Web方式OTA升级6.1 基础OTA代码6.2 新固件库代码在前面的文章中,我们在Arduino IDE的网络端口中,实现…

LeetCode 77.组合

题目&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 方法&#xff1a;灵神-组合型回溯 剪枝 class Solution {private int k;private final List<Integer> path new ArrayList<>();…

反序列化 [网鼎杯 2020 朱雀组]phpweb 1

打开题目 我们发现这个页面一直在不断的刷新 我们bp抓包一下看看 我们发现index.php用post方式传了两个参数上去&#xff0c;func和p 我们需要猜测func和p两个参数之间的关系&#xff0c;可以用php函数MD5测一下看看 我们在响应处得到了一串密文&#xff0c;md5解密一下看看 发…

Windows11安装使用Oracle21C详细步骤<图文保姆级>新版本

Windows11安装使用Oracle21C详细步骤<图文保姆级>新版本 Database Software Downloads | Oracle 中国 下载完成后解压缩 双击setup.exe 打开安装页面 同意下一步 更改自己的路径点击下一步 输入密码 下一步安装等待即可 等待加载配置时间有点久 完成即可 使用 搜索…

【Kubernetes】四层代理Service

Service四层代理 一、Service概念原理1.1、为什么要有Service1.2、Service概述1.3、工作原理1.4、三类IP地址【1】Node Network&#xff08;节点网络&#xff09;【2】Pod network&#xff08;pod 网络&#xff09;【3】Cluster Network&#xff08;服务网络&#xff09; 二、S…