【JavaEE】多线程代码案例(2)
🎏🎏🎏个人主页🎏🎏🎏
🎏🎏🎏JavaEE专栏🎏🎏🎏
🎏🎏🎏上一篇文章:多线程代码案例(1)🎏🎏🎏
文章目录
- 1.线程池
- 1.1概念
- 1.2线程池如何提高效率
- 1.3标准库线程池的参数分析
- 1.4模拟实现一个线程池
- 1.4.1一个固定数目的线程池
- 1.4.2含有最大线程数的线程池
- 1.5线程池优点
- 2.定时器
- 2.1概念
- 2.2Java标准库中的定时器(Timer)
- 2.3模拟实现定时器
- 2.3.1定时器的需求
- 2.3.2实现需求的技术
- 2.3.3代码的实现
- 1.4总结
1.线程池
1.1概念
将你需要用到的线程提前创建好,然后放到用户态通过数据结构的形式来管理。
1.2线程池如何提高效率
我们直接创建线程是内核态与用户态两一起配合完成的,如果频繁的去创建线程销毁线程,这样效率就会大大降低并且内核在完成一些任务是不可控的,面对这种情况我们就可以提前将我们需要用到的线程创建好放在用户态种通过数据结构管理起来,当需要使用的时候就通过用户态来调用,不要用就放回用户态中,减少内核态的参与相当于减少了不可控性那么效率就会提高。
1.3标准库线程池的参数分析
ThreadPoolExecutor
- int corePoolSize int maximumPoolSize
corepoolSize(核心线程数)——根据CPU的逻辑核心数决定的
maximumPoolSize(最大线程数)——由核心线程数+非核心线程数
对线程池中的线程分为两种:核心线程和非核心线程
核心线程:当线程池被创建了,核心线程也就有了。
非核心线程:当任务过多的时候,核心线程处理不过来的时候,线程池就会临时创建线程来分担任务,当任务变轻的时候,那么这些非核心线程就会被回收,这样当任务繁重的时候,增加一些非核心线程就会提高效率,当任务空闲的时候就可以减少开销。
那么最大的线程数应该设多少比较合适呢?
关于设多少比较合适不仅仅和电脑的配置有关系还和代码类型有关系。
代码类型在理想的情况下分为两种:CPU密集类型和IO密集类型
CPU密集类型:
代码中基本都是算术运算,条件判断,循环判断,函数调用这些都是需要大量调用CPU来参加工作的,那么这种最大的线程数应该要小于等于逻辑核心数。
IO密集类型:
IO类型的每一个线程消耗的CPU只有一点点,影响的主要是其他方面比如网卡带宽,硬盘访问…,那么最大线程数可以大于等于逻辑核心数。
但我们生活中可不会有这种理想情况发生,一般都是CPU密集型于IO密集型结合的情况,那么这个最大的线程数怎么去确定呢,可以根据做实验的方式(控制变量法)来确定一个相对正确的数据。 - long keepAliveTime TimeUnit unit
long keepAliveTime——允许非核心线程最大的空闲时间
TimeUnit unit——空闲时间单位
给定时间可以增加容错率,防止任务少的时候突然任务剧增,这样就可以给回收非核心线程缓冲时间。 - BlockingQueue workQueue
BlockingQueue workQueue——线程池的任务队列
线程池会提供submit方法,让其他线程将任务提交给线程池,此时的线程池就需要队列这样的数据结构,将任务管理起来,这个队列存储的元素其实就是Runnable对象,要执行的逻辑其实就是run方法中的内容 - ThreadFactory threadFactory
ThreadFactory threadFactory——java标准库中提供的工厂类
当我们需要创建一个点,有两种方式一种是笛卡尔坐标表示法,另一种是极坐标表示法
class Point {point(double x,double y) {}point(double r,double a) {}
}
此时的两种方式都是通过构造方法来创建的,但是这两种方法构成不了重载,所以无法实现,因为在某些特殊情况构造方法会带来一些麻烦,就出现了工厂方法来封装一些这些构造方法,这种模式叫工厂模式
class Point {public static point makePointByXY(double x, double y) {Point p = new Point();p.set(x);p.set(y);return p;}public static point makePointByRA(double r, double a) {Point p = new Point();p.set(r);p.set(a);return p;}
}
上述代码就是一种通过工厂方法来封装这些构造点的方法。
5. RejectedExecutionHandler handler
RejectedExecutionHandler handler——拒绝策略,是一种以枚举的方式表示的。
- AbortPolicy():超出负荷,直接抛出异常
- CallerRunsPolicy():调用者负责处理多出来的任务
- DiscardOldestPolicy():丢弃队列中最老的任务
- DiscardPolicy():丢弃新来的任务
由于ThreadPoolExecutor用起来非常费劲,于是就提供了几个工厂类例如:Executor
通过工厂类中提供的方法可以创建线程池的几种方式: - Executors.newFixedThreadPool()——创建固定线程数目的线程池
- Executors.newSingleThreadExecutor()——创建一个只包含单个线程的线程池
- Executors.newScheduledThreadPool(4)——创建一个固定线程个数, 但是任务延时执行的线程池
创建一个固定线程数的线程池:
public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(10);for (int i = 0; i <=50000 ; i++) {int id = i;service.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello " + id + ", " + Thread.currentThread().getName());}});}
}
1.4模拟实现一个线程池
- 需要若干个线程
- 需要任务队列
- 需要submit方法
1.4.1一个固定数目的线程池
//创建一个简单的线程
public class MyThreadPollBasicEdition {//创建一个任务队列public BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);//初始化线程池public MyThreadPollBasicEdition(int n) {for (int i = 0; i < n; i++) {Thread t = new Thread(()-> {try {while(true) {Runnable runnable = queue.take();runnable.run();}} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();}}//提供submit方法public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}public static void main(String[] args) throws InterruptedException {MyThreadPollBasicEdition myThreadPollBasicEdition = new MyThreadPollBasicEdition(10);for (int i = 0; i < 50000; i++) {int id = i;myThreadPollBasicEdition.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello " + id + ", " + Thread.currentThread().getName());}});}}
}
1.4.2含有最大线程数的线程池
ic class MyThreadPollAdvancedEdition {//创建一个任务队列的对象public BlockingQueue<Runnable> queue = new ArrayBlockingQueue(1000);//创建一个最大线程数public int maxThreadSize = 0;//创建一个集合来存储若干个线程public List<Thread> threadList = new ArrayList<>();//创建构造方法public MyThreadPollAdvancedEdition(int corePoolSize, int maxThreadSize) {this.maxThreadSize = maxThreadSize;for (int i = 0; i < corePoolSize; i++) {Thread t = new Thread(()->{try {while (true) {Runnable runnable = queue.take();runnable.run();}}catch (InterruptedException e) {e.printStackTrace();}});t.start();threadList.add(t);}}public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);//如果队列中的任务过多,导致线程不够用,可以增加一些线程if(queue.size() >=200 && threadList.size() < maxThreadSize) {Thread thread = new Thread(()-> {try {while(true) {Runnable runnable1 = queue.take();runnable1.run();}}catch (InterruptedException e) {e.printStackTrace();}});thread.start();threadList.add(thread);}}public static void main(String[] args) throws InterruptedException {MyThreadPollAdvancedEdition myThreadPollAdvancedEdition = new MyThreadPollAdvancedEdition(10,20);for (int i = 0; i < 50000; i++) {int id = i;myThreadPollAdvancedEdition.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello " + id + ", " + Thread.currentThread().getName());}});}}
}
1.5线程池优点
- 降低资源消耗:减少线程的创建和销毁带来的性能开销。
- 提高响应速度:当任务来时可以直接使用,不用等待线程创建
- 可管理性: 进行统一的分配,监控,避免大量的线程间因互相抢占系统资源导致的阻塞现象。
2.定时器
2.1概念
用于实现定时操作、周期性任务和超时控制的作用
2.2Java标准库中的定时器(Timer)
Timer提供了一个schedule方法
public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello,2000");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello,1000");}},1000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello,3000");}},3000);
}
2.3模拟实现定时器
2.3.1定时器的需求
- 能够延时执行任务和定时执行任务
- 能够管理多个任务
2.3.2实现需求的技术
- 需要一个描述任务和指定时间的类(本质就是一个Runnable)
- 需要一个数据结构来管理多个任务(优先级队列)
- 需要一个线程来扫描数据结构管理的任务
2.3.3代码的实现
//1.定义一个TimeTask类表示一个任务,这个类中需要任务执行的时间和描述任务。
class TimeTask implements Comparable<TimeTask> {public Runnable runnable;//此时的time不是程序等待的时间,而是一个绝对时间public long time;public TimeTask(Runnable runnable,long delay) {this.runnable = runnable;//手动换算时间,加一个时间戳将相对时间换算成绝对时间this.time = System.currentTimeMillis() + delay;}public void run() {runnable.run();}public long getTime() {return time;}@Overridepublic int compareTo(TimeTask o) {return (int) (this.time - o.time);}
}
//2.定义一个数据结构来管理多个任务,此处我们优先级队列来管理多个任务,因为用其他的数据结构去管理的话,
// 就需要不断去扫描数据结构中满足要求的成员,遇到数据量庞大的那么开销就巨大,得不偿失,
// 用优先级队列可以避免这种情况,由于要求等待时间短的先运行,那么我们可以定义一个小根堆。
class MyTime{Object locker = new Object();public PriorityQueue<TimeTask> queue = new PriorityQueue<>();//初始化线程,并且调用任务public MyTime() {//定义一个扫描线程来获取堆顶任务Thread t = new Thread(()-> {try {while(true) {synchronized (locker) {if (queue.size() == 0) {locker.wait();}//取小堆中堆顶的任务TimeTask task = queue.peek();//获取当前的时间戳long curTime = System.currentTimeMillis();//看任务的时间是否到了if(curTime >= task.getTime()) {//时间到了,则执行任务task.run();//任务执行完之后,则将队列中的堆顶任务消除queue.poll();} else {//任务时间没到,则堵塞,阻塞多久?堵塞任务等待的时间locker.wait(task.getTime() - curTime);}}}} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();}//提供一个schedule方法来创建任务public void schedule(Runnable runnable,long delay) {synchronized (locker) {TimeTask timeTask = new TimeTask(runnable,delay);queue.offer(timeTask);//唤醒调用任务的线程locker.notify();}}
}
public class MyTimerTest {public static void main(String[] args) {MyTime myTime = new MyTime();myTime.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello,1000");}},1000);myTime.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello,2000");}},2000);myTime.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello,3000");}},3000);}
}
1.4总结
- 创建一个类,表示一个任务(Runnable 任务本体 time任务的执行时间)
- 引入数据结构来管理多个任务(用的是优先级队列,省去遍历的开销)
- 引入扫描线程,不停的循环获取队列队首任务,判定是否到时间,到时间就执行,并且出队列没到时间就阻塞。
- 引入锁,针对队列出和入的操作
- 解决忙等问题,引入wait和notify,队列为空wait(死等)队首任务没到时间wait(带有超时时间)这里不要用sleep(sleep通过interrupt唤醒是非常规手段,sleep不会释放锁,会影响后续插入任务)
- 引入比较规则,让TimeTask可以按照时间先后来制定优先级。
相关文章:

【JavaEE】多线程代码案例(2)
🎏🎏🎏个人主页🎏🎏🎏 🎏🎏🎏JavaEE专栏🎏🎏🎏 🎏🎏🎏上一篇文章:多线程代码案例(1)&a…...

Halcon支持向量机
一 支持向量机 1 支持向量机介绍: 支持向量机(Support Vector Machine,SVM)是Corinna Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别表现出许多特有的优势。 2 支持向量机原理: 在n维空间中找到一个分类超平面…...
【Python机器学习】模型评估与改进——在模型选择中使用评估指标
我们通常希望,在使用GridSearchCV或cross_val_score进行模型选择时能够使用AUC等指标。scikit-learn提供了一种非常简单的实现方法,那就是scoring参数,它可以同时用于GridSearchCV和cross_val_score。你只需要提供一个字符串,用于…...

【C语言】union 关键字
在C语言中,union关键字用于定义联合体。联合体是一种特殊的数据结构,它允许不同的数据类型共享同一段内存。所有联合体成员共享同一个内存位置,因此联合体的大小取决于其最大成员的大小。 定义和使用联合体 基本定义 定义一个联合体类型时…...

电脑回收站删除的文件怎么恢复?5个恢复方法详解汇总!
电脑回收站删除的文件怎么恢复?在我们日常使用电脑的过程中,难免会遇到误删文件的情况。一旦发现自己误删文件了,先不要着急,还是有很多方法可以找回的。市面上还是有很多好用的文件恢复软件可以使用,具体介绍如下。 本…...
mac 安装cnpm 淘宝镜像记录
mac 安装cnpm 淘宝镜像记录 本文介绍了在安装cnpm时遇到权限问题的解决方案,包括使用sudo,处理SSL证书过期,以及因版本不一致导致的错误处理方法,步骤包括设置npm配置、卸载和重新安装cnpm到特定版本。 安装 npm install cnpm …...
ArcGIS Pro SDK (七)编辑 11 撤销重做
ArcGIS Pro SDK (七)编辑 11 撤销&重做 文章目录 ArcGIS Pro SDK (七)编辑 11 撤销&重做1 撤消/重做最近的操作 环境:Visual Studio 2022 .NET6 ArcGIS Pro SDK 3.0 1 撤消/重做最近的操作 //撤销 if (MapV…...
Excel 中的元素定位:相对定位、绝对定位和混合定位
在Excel中,单元格引用有三种主要类型:相对定位、绝对定位和混合定位。 这些类型主要用于公式和函数中,决定在复制或拖动公式时引用如何变化。 1. 相对定位 相对定位指的是不带“$”符号的单元格引用,例如 A1。 这种引用方式在…...
Idea2024安装后点击无响应
问题 最近因工作需要,升级一下 idea 版本,之前一直使用的是2020版本,下载最新的2024版本(下载的 zip 包免安装模式,之前使用的2020版本也是免安装的,因为是免安装的,所以之前的版本也没有删除&…...
如何提高实验室分析结果的准确性呢
要提高实验室分析结果的准确性,可以从以下几个方面着手: 1、选择合适的实验方法 不同的实验方法具有不同的优缺点,实验方法的准确度直接影响测定结果的准确度。因此,在选择实验方法时,需要根据实验目的、实验原理、实…...
Perl 格式化输出:提升代码可读性的技巧
引言 Perl 是一种功能强大的脚本语言,广泛用于文本处理、系统管理、网络编程等多个领域。在 Perl 编程中,代码的格式化输出不仅有助于提升代码的可读性,还能增强程序的用户体验。本文将详细介绍如何在 Perl 中实现代码的格式化输出。 Perl …...

JavaScript基础-函数(完整版)
文章目录 函数基本使用函数提升函数参数arguments对象(了解)剩余参数(重点)展开运算符(...) 逻辑中断函数参数-默认参数函数返回值-return作用域(scope)全局作用域局部作用域变量的访问原则垃圾回收机制闭包 匿名函数函数表达式立即执行函数 箭头函数箭头…...
AI开发者的新选择:Mojo编程语言
随着人工智能技术的迅猛发展,编程语言的选择在AI项目的成功中扮演着至关重要的角色。近年来,Mojo编程语言作为一种专为AI开发者设计的新兴语言,逐渐引起了广泛关注。本文将详细介绍Mojo编程语言的特点、优势及其在AI开发中的应用。 目录 Mo…...
软考(高项)系统分析师--论软件开发模型及应用
文章目录 前言一、前期准备:二、论文部分: 前言 本文对系统分析师,软件开发模型及其应用文章进行展示,可以拷贝后直接粘贴到word 文档中。 一、前期准备: 项目主体功能项目背景常用的软件开发模型:瀑布模型ÿ…...
同一天提档又撤档!电影《野孩子》宣布取消7月10日公映安排——浔川电影报
同一天提档又撤档! 7月3日晚上10点,电影野孩子 发声明官宣撤档,“由于后期进度原因,电影《野孩子》将取消7月10日的公映安排,我们向各影管院线的同仁及所有观众朋友们致以最诚挚的歉意,谢谢大家这段时间的…...
Shell编程之免交互
一、Here Document免交互 1:概述 Here Document 是一个特殊用途的代码块,它在 Linux Shell 中使用 I/O 重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令,Here Document 是标准输入的一种替代品 语法…...

基于opencv的斜光测距及python实现
1.前言 最近做了一个基于opencv的斜光测距的小项目,东西不多,但是很有意思,值得拿出来学一学。项目里面需要比较精确的定位功能,将前人matlab代码移植到python上,并且做了一些优化,简化逻辑(毕竟我是专业的…...
梯度下降算法
占楼,明天写...
第5章:软件工程
第5章:软件工程 软件工程概述 软件生命周期 软件过程 1.能力成熟度模型(CMM) CMM(能力成熟度模型)是一个评估和确定组织软件过程成熟度的模型。它最早于1987年由美国国防部软件工程研究所(SEI)提出,其目的…...
cefsharp在splitContainer.Panel2中显示调试工具DevTools(非弹出式)含源代码
一、弹出式调试工具 (ShowDevTools) ChromiumWebBrowser webbrowser; public void showDevTools(){//定位到某元素webbrowser.ShowDevTools(null, parameters.XCoord, parameters.YCoord);...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...