【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");
            });
        }
    }

}

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

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

相关文章

2024年网络安全竞赛-Web安全应用

Web安全应用 (一)拓扑图 任务环境说明: 1.获取PHP的版本号作为Flag值提交;(例如:5.2.14) 2.获取MySQL数据库的版本号作为Flag值提交;(例如:5.0.22) 3.获取系统的内核版本号作为Flag值提交;(例如:2.6.18) 4.获取网站后台管理员admin用户的密码作为Flag值提交…

我的隐私计算学习——隐私集合求交(1)

笔记内容来自多本书籍、学术资料、白皮书及ChatGPT等工具&#xff0c;经由自己阅读后整理而成。 &#xff08;一&#xff09;PSI的介绍 隐私计算关键技术&#xff1a;隐私集合求交&#xff08;PSI&#xff09;原理介绍 隐私计算关键技术&#xff1a;隐私集合求交&#xff08…

【基于Flask、MySQL和Echarts的热门游戏数据可视化平台设计与实现】

基于Flask、MySQL和Echarts的热门游戏数据可视化平台设计与实现 前言数据获取与清洗数据集数据获取数据清洗 数据分析与可视化数据分析功能可视化功能 创新点结语 前言 随着游戏产业的蓬勃发展&#xff0c;了解游戏销售数据对于游戏从业者和游戏爱好者都至关重要。为了更好地分…

【Python数据结构与算法】—— 搜索算法 | 期末复习不挂科系列

​ &#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 数据结构与算法&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 这篇博客主要探索的是计算机科学常见问题---搜索算法 “时间紧&#xff0c;任务重&#xff01;” 话不多说&#xff0c;开始今天…

高工氢电年会 | 未势能源解超朋博士受邀出席并做主题演讲

12月4日&#xff0c;以“战略重构 商业觉醒”为主题的2023高工氢电年会在深圳举办&#xff0c;未势能源副总裁解超朋博士受邀出席开幕式论坛&#xff0c;以《把握机遇、直面挑战&#xff0c;迎接氢车规模化推广时代》为主题发表演讲&#xff0c;并参与圆桌论坛研讨。 氢势已来&…

Linux系统中进程的背景(只从数据层面和硬件层面分析)

目录 1、冯诺依曼体系 2、管理的本质 3、 操作系统是如何对硬件进行管理的 4、 计算机的软硬件结构 5、 进程的组成 1、冯诺依曼体系 冯诺依曼是很早就提出的一个体系结构&#xff0c;他是将计算机分成五个部分&#xff0c;输入设备、输出设备、存储器、运算器和控制器。其中运…

Nature Communications 高时空分辨率的机器人传感系统及其在纹理识别方面的应用

前沿速览&#xff1a; 现有的触觉传感器虽然可以精确的检测压力、剪切力和应变等物理刺激&#xff0c;但还难以像人类手指一样通过滑动触摸&#xff0c;同时获取静态压力与高频振动来实现精确的纹理识别。为了解决这一问题&#xff0c;来自南方科技大学的郭传飞团队提出了衔接…

英伟达危机大爆发!一夜之间,四面楚歌

今年以来&#xff0c;AI大模型明争暗斗、百花齐放。 但不管各种大模型打的有多厉害&#xff0c;很多人都认为“卖铲子”的英伟达才是最大赢家。 看一下英伟达今年的股票就知道英伟达赚的是多么盆满钵满。 英伟达CEO黄仁勋在发布 H200显卡时&#xff0c;应该是今年最意气风发的…

Gan论文阅读笔记

GAN论文阅读笔记 2014年老论文了&#xff0c;主要记录一些重要的东西。论文链接如下&#xff1a; Generative Adversarial Nets (neurips.cc) 文章目录 GAN论文阅读笔记出发点创新点设计训练代码网络结构代码测试代码 出发点 Deep generative models have had less of an impac…

C/C++ 判断str1能不能由str2里面的字符构成,如果可以,返回true;否则,返回false

题目: 给两个字符串&#xff1a;str1和str2&#xff0c;判断str1能不能由str2里面的字符构成。 如果可以,返回true&#xff1b; 否则,返回false。 限制&#xff1a; str2 中的每个字符只能在str1中使用一次。 示例 1&#xff1a; 输入&#xff1a;str1 "a&q…

CSS3技巧36:让内容垂直居中的三种方式

让内容垂直居中&#xff0c;是一个很重要的应用情景&#xff0c;在很多场合都会需要。这也是面试的时候&#xff0c;一些考官喜欢拿来初面的小题目。 这里&#xff0c;小结下让内容垂直居中的三种方式。 当然&#xff0c;读者如果有更好的方法&#xff0c;也可以提出来。 基本…

使用Java实现汉诺塔问题

文章目录 汉诺塔问题 今天和大家来看看汉诺塔问题&#xff0c;这也是一个经典的算法 汉诺塔问题 分治算法经典问题&#xff1a;汉诺塔问题 汉诺塔的传说 汉诺塔&#xff1a;汉诺塔&#xff08;又称河内塔&#xff09;问题是源于印度一个古老传说的益智玩具。大梵天创造世界的…

面试必考精华版Leetcode875. 爱吃香蕉的珂珂

题目&#xff1a; 代码(首刷看解析&#xff09;&#xff1a; class Solution { public:int minEatingSpeed(vector<int>& piles, int h) {int low 1;int high 0;for(int pile:piles){highmax(high,pile);}int k high;while(low<high){int speed (high-low)/2l…

『 MySQL数据库 』聚合统计

文章目录 前言 &#x1f951;&#x1f95d; 聚合函数&#x1f353; COUNT( ) 查询数据数量&#x1f353; SUM( ) 查询数据总和&#x1f353; AVG( ) 查询数据平均值&#x1f353; MAX( ) 查询数据最大值&#x1f353; MIN( ) 查询数据最小值 &#x1f95d; 数据分组GROUP BY子句…

期待一下elasticsearch还未发布的8.12版本,由lucene底层带来的大幅度提升

现在是北京时间23年12月10日。当前es最新版本还是es8.11版本。我们可以期待一下不久的将来&#xff0c;es的8.12版本看到大幅度的检索性能提升。受益于 Lucene 9.9版本&#xff0c;内核带来的大幅提升&#xff01; 此次向量检索利用底层指令fma会性能提升5%。并且还提供了向量点…

零一万物模型折腾笔记:官方 Yi-34B 模型基础使用

当争议和流量都消失后&#xff0c;或许现在是个合适的时间点&#xff0c;来抛开情绪、客观的聊聊这个 34B 模型本身&#xff0c;尤其是实践应用相关的一些细节。来近距离看看这个模型在各种实际使用场景中的真实表现和对硬件的性能要求。 或许&#xff0c;这会对也想在本地私有…

NLP项目实战01--电影评论分类

介绍&#xff1a; 欢迎来到本篇文章&#xff01;在这里&#xff0c;我们将探讨一个常见而重要的自然语言处理任务——文本分类。具体而言&#xff0c;我们将关注情感分析任务&#xff0c;即通过分析电影评论的情感来判断评论是正面的、负面的。 展示&#xff1a; 训练展示如下…

Android笔记(十七):PendingIntent简介

PendingIntent翻译成中文为“待定意图”&#xff0c;这个翻译很好地表示了它的涵义。PendingIntent描述了封装Intent意图以及该意图要执行的目标操作。PendingIntent封装Intent的目标行为的执行是必须满足一定条件&#xff0c;只有条件满足&#xff0c;才会触发意图的目标操作。…

HCIP —— BGP 基础 (上)

BGP --- 边界网关协议 &#xff08;路径矢量协议&#xff09; IGP --- 内部网关协议 --- OSPF RIP ISIS EGP --- 外部网关协议 --- EGP BGP AS --- 自治系统 由单一的组织或者机构独立维护的网络设备以及网络资源的集合。 因 网络范围太大 需 自治 。 为区分不同的AS&#…

C#,图算法——以邻接节点表示的图最短路径的迪杰斯特拉(Dijkstra)算法C#程序

1 文本格式 using System; using System.Text; using System.Linq; using System.Collections; using System.Collections.Generic; namespace Legalsoft.Truffer.Algorithm { public class Node // : IComparable<Node> { private int vertex, weigh…