当前位置: 首页 > news >正文

【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
在这里插入图片描述

  1. int corePoolSize int maximumPoolSize
    corepoolSize(核心线程数)——根据CPU的逻辑核心数决定的
    maximumPoolSize(最大线程数)——由核心线程数+非核心线程数
    对线程池中的线程分为两种:核心线程和非核心线程
    核心线程:当线程池被创建了,核心线程也就有了。
    非核心线程:当任务过多的时候,核心线程处理不过来的时候,线程池就会临时创建线程来分担任务,当任务变轻的时候,那么这些非核心线程就会被回收,这样当任务繁重的时候,增加一些非核心线程就会提高效率,当任务空闲的时候就可以减少开销。
    那么最大的线程数应该设多少比较合适呢?
    关于设多少比较合适不仅仅和电脑的配置有关系还和代码类型有关系。
    代码类型在理想的情况下分为两种:CPU密集类型和IO密集类型
    CPU密集类型:
    代码中基本都是算术运算,条件判断,循环判断,函数调用这些都是需要大量调用CPU来参加工作的,那么这种最大的线程数应该要小于等于逻辑核心数。
    IO密集类型:
    IO类型的每一个线程消耗的CPU只有一点点,影响的主要是其他方面比如网卡带宽,硬盘访问…,那么最大线程数可以大于等于逻辑核心数。
    但我们生活中可不会有这种理想情况发生,一般都是CPU密集型于IO密集型结合的情况,那么这个最大的线程数怎么去确定呢,可以根据做实验的方式(控制变量法)来确定一个相对正确的数据。
  2. long keepAliveTime TimeUnit unit
    long keepAliveTime——允许非核心线程最大的空闲时间
    TimeUnit unit——空闲时间单位
    给定时间可以增加容错率,防止任务少的时候突然任务剧增,这样就可以给回收非核心线程缓冲时间。
  3. BlockingQueue workQueue
    BlockingQueue workQueue——线程池的任务队列
    线程池会提供submit方法,让其他线程将任务提交给线程池,此时的线程池就需要队列这样的数据结构,将任务管理起来,这个队列存储的元素其实就是Runnable对象,要执行的逻辑其实就是run方法中的内容
  4. 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——拒绝策略,是一种以枚举的方式表示的。

  1. AbortPolicy():超出负荷,直接抛出异常
  2. CallerRunsPolicy():调用者负责处理多出来的任务
  3. DiscardOldestPolicy():丢弃队列中最老的任务
  4. DiscardPolicy():丢弃新来的任务
    由于ThreadPoolExecutor用起来非常费劲,于是就提供了几个工厂类例如:Executor
    通过工厂类中提供的方法可以创建线程池的几种方式:
  5. Executors.newFixedThreadPool()——创建固定线程数目的线程池
  6. Executors.newSingleThreadExecutor()——创建一个只包含单个线程的线程池
  7. 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模拟实现一个线程池

  1. 需要若干个线程
  2. 需要任务队列
  3. 需要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线程池优点

  1. 降低资源消耗:减少线程的创建和销毁带来的性能开销。
  2. 提高响应速度:当任务来时可以直接使用,不用等待线程创建
  3. 可管理性: 进行统一的分配,监控,避免大量的线程间因互相抢占系统资源导致的阻塞现象。

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定时器的需求

  1. 能够延时执行任务和定时执行任务
  2. 能够管理多个任务

2.3.2实现需求的技术

  1. 需要一个描述任务和指定时间的类(本质就是一个Runnable)
  2. 需要一个数据结构来管理多个任务(优先级队列)
  3. 需要一个线程来扫描数据结构管理的任务

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总结

  1. 创建一个类,表示一个任务(Runnable 任务本体 time任务的执行时间)
  2. 引入数据结构来管理多个任务(用的是优先级队列,省去遍历的开销)
  3. 引入扫描线程,不停的循环获取队列队首任务,判定是否到时间,到时间就执行,并且出队列没到时间就阻塞。
  4. 引入锁,针对队列出和入的操作
  5. 解决忙等问题,引入wait和notify,队列为空wait(死等)队首任务没到时间wait(带有超时时间)这里不要用sleep(sleep通过interrupt唤醒是非常规手段,sleep不会释放锁,会影响后续插入任务)
  6. 引入比较规则,让TimeTask可以按照时间先后来制定优先级。

相关文章:

【JavaEE】多线程代码案例(2)

&#x1f38f;&#x1f38f;&#x1f38f;个人主页&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;JavaEE专栏&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;上一篇文章&#xff1a;多线程代码案例(1)&a…...

Halcon支持向量机

一 支持向量机 1 支持向量机介绍&#xff1a; 支持向量机(Support Vector Machine&#xff0c;SVM)是Corinna Cortes和Vapnik于1995年首先提出的&#xff0c;它在解决小样本、非线性及高维模式识别表现出许多特有的优势。 2 支持向量机原理: 在n维空间中找到一个分类超平面…...

【Python机器学习】模型评估与改进——在模型选择中使用评估指标

我们通常希望&#xff0c;在使用GridSearchCV或cross_val_score进行模型选择时能够使用AUC等指标。scikit-learn提供了一种非常简单的实现方法&#xff0c;那就是scoring参数&#xff0c;它可以同时用于GridSearchCV和cross_val_score。你只需要提供一个字符串&#xff0c;用于…...

【C语言】union 关键字

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

电脑回收站删除的文件怎么恢复?5个恢复方法详解汇总!

电脑回收站删除的文件怎么恢复&#xff1f;在我们日常使用电脑的过程中&#xff0c;难免会遇到误删文件的情况。一旦发现自己误删文件了&#xff0c;先不要着急&#xff0c;还是有很多方法可以找回的。市面上还是有很多好用的文件恢复软件可以使用&#xff0c;具体介绍如下。 本…...

mac 安装cnpm 淘宝镜像记录

mac 安装cnpm 淘宝镜像记录 本文介绍了在安装cnpm时遇到权限问题的解决方案&#xff0c;包括使用sudo&#xff0c;处理SSL证书过期&#xff0c;以及因版本不一致导致的错误处理方法&#xff0c;步骤包括设置npm配置、卸载和重新安装cnpm到特定版本。 安装 npm install cnpm …...

ArcGIS Pro SDK (七)编辑 11 撤销重做

ArcGIS Pro SDK &#xff08;七&#xff09;编辑 11 撤销&重做 文章目录 ArcGIS Pro SDK &#xff08;七&#xff09;编辑 11 撤销&重做1 撤消/重做最近的操作 环境&#xff1a;Visual Studio 2022 .NET6 ArcGIS Pro SDK 3.0 1 撤消/重做最近的操作 //撤销 if (MapV…...

Excel 中的元素定位:相对定位、绝对定位和混合定位

在Excel中&#xff0c;单元格引用有三种主要类型&#xff1a;相对定位、绝对定位和混合定位。 这些类型主要用于公式和函数中&#xff0c;决定在复制或拖动公式时引用如何变化。 1. 相对定位 相对定位指的是不带“$”符号的单元格引用&#xff0c;例如 A1。 这种引用方式在…...

Idea2024安装后点击无响应

问题 最近因工作需要&#xff0c;升级一下 idea 版本&#xff0c;之前一直使用的是2020版本&#xff0c;下载最新的2024版本&#xff08;下载的 zip 包免安装模式&#xff0c;之前使用的2020版本也是免安装的&#xff0c;因为是免安装的&#xff0c;所以之前的版本也没有删除&…...

如何提高实验室分析结果的准确性呢

要提高实验室分析结果的准确性&#xff0c;可以从以下几个方面着手&#xff1a; 1、选择合适的实验方法 不同的实验方法具有不同的优缺点&#xff0c;实验方法的准确度直接影响测定结果的准确度。因此&#xff0c;在选择实验方法时&#xff0c;需要根据实验目的、实验原理、实…...

Perl 格式化输出:提升代码可读性的技巧

引言 Perl 是一种功能强大的脚本语言&#xff0c;广泛用于文本处理、系统管理、网络编程等多个领域。在 Perl 编程中&#xff0c;代码的格式化输出不仅有助于提升代码的可读性&#xff0c;还能增强程序的用户体验。本文将详细介绍如何在 Perl 中实现代码的格式化输出。 Perl …...

JavaScript基础-函数(完整版)

文章目录 函数基本使用函数提升函数参数arguments对象&#xff08;了解&#xff09;剩余参数(重点)展开运算符(...) 逻辑中断函数参数-默认参数函数返回值-return作用域(scope)全局作用域局部作用域变量的访问原则垃圾回收机制闭包 匿名函数函数表达式立即执行函数 箭头函数箭头…...

AI开发者的新选择:Mojo编程语言

随着人工智能技术的迅猛发展&#xff0c;编程语言的选择在AI项目的成功中扮演着至关重要的角色。近年来&#xff0c;Mojo编程语言作为一种专为AI开发者设计的新兴语言&#xff0c;逐渐引起了广泛关注。本文将详细介绍Mojo编程语言的特点、优势及其在AI开发中的应用。 目录 Mo…...

软考(高项)系统分析师--论软件开发模型及应用

文章目录 前言一、前期准备&#xff1a;二、论文部分: 前言 本文对系统分析师&#xff0c;软件开发模型及其应用文章进行展示&#xff0c;可以拷贝后直接粘贴到word 文档中。 一、前期准备&#xff1a; 项目主体功能项目背景常用的软件开发模型&#xff1a;瀑布模型&#xff…...

同一天提档又撤档!电影《野孩子》宣布取消7月10日公映安排——浔川电影报

同一天提档又撤档&#xff01; 7月3日晚上10点&#xff0c;电影野孩子 发声明官宣撤档&#xff0c;“由于后期进度原因&#xff0c;电影《野孩子》将取消7月10日的公映安排&#xff0c;我们向各影管院线的同仁及所有观众朋友们致以最诚挚的歉意&#xff0c;谢谢大家这段时间的…...

Shell编程之免交互

一、Here Document免交互 1&#xff1a;概述 Here Document 是一个特殊用途的代码块&#xff0c;它在 Linux Shell 中使用 I/O 重定向的方式将命令列表提供给交互式程序或命令&#xff0c;比如 ftp、cat 或 read 命令&#xff0c;Here Document 是标准输入的一种替代品 语法…...

基于opencv的斜光测距及python实现

1.前言 最近做了一个基于opencv的斜光测距的小项目&#xff0c;东西不多&#xff0c;但是很有意思&#xff0c;值得拿出来学一学。项目里面需要比较精确的定位功能&#xff0c;将前人matlab代码移植到python上&#xff0c;并且做了一些优化&#xff0c;简化逻辑(毕竟我是专业的…...

梯度下降算法

占楼&#xff0c;明天写...

第5章:软件工程

第5章&#xff1a;软件工程 软件工程概述 软件生命周期 软件过程 1.能力成熟度模型(CMM) CMM&#xff08;能力成熟度模型&#xff09;是一个评估和确定组织软件过程成熟度的模型。它最早于1987年由美国国防部软件工程研究所&#xff08;SEI&#xff09;提出&#xff0c;其目的…...

cefsharp在splitContainer.Panel2中显示调试工具DevTools(非弹出式)含源代码

一、弹出式调试工具 (ShowDevTools) ChromiumWebBrowser webbrowser; public void showDevTools(){//定位到某元素webbrowser.ShowDevTools(null, parameters.XCoord, parameters.YCoord);...

GLM-4.1V-9B-Base成本优化指南:GPU显存管理与推理性能调优

GLM-4.1V-9B-Base成本优化指南&#xff1a;GPU显存管理与推理性能调优 1. 为什么需要关注大模型推理成本 大模型在带来强大能力的同时&#xff0c;也伴随着高昂的GPU算力成本。GLM-4.1V-9B-Base作为一款9B参数量的视觉语言大模型&#xff0c;在实际部署中常常面临显存不足、推…...

2025年11月一区SCI-壁虎优化算法Gekko Japonicus Algorithm-附Matlab免费代码

引言 近年来&#xff0c;在合理框架内求解优化问题的元启发式算法的发展引起了全球科学界的极大关注。本期介绍一种新的创新算法——壁虎优化算法Gekko Japonicus Algorithm&#xff0c;GJA。该算法的灵感主要来自于壁虎的捕食策略和生存行为。通过模拟壁虎的混合运动模式、定…...

Kook Zimage 真实幻想 Typora文档集成方案

Kook Zimage 真实幻想 Typora文档集成方案 1. 引言 技术文档写作最头疼的是什么&#xff1f;文字描述得再生动&#xff0c;也不如一张直观的图片来得有说服力。传统的文档创作流程中&#xff0c;我们需要先在专门的AI绘图工具中生成图片&#xff0c;然后下载保存&#xff0c;…...

OpenCASCADE实战:如何正确获取3D模型面的法向(附完整代码示例)

OpenCASCADE实战&#xff1a;3D模型面法向的高效获取与方向校正 在三维建模与几何处理领域&#xff0c;准确获取模型表面的法向向量是许多高级操作的基础。无论是进行碰撞检测、光照计算还是有限元分析&#xff0c;法向数据的准确性直接影响最终结果的可靠性。OpenCASCADE作为一…...

让 AI 听懂业务、直接干活:销售易 NeoAgent 2.0 的三大跃迁

当软件行业仍在争论“AI是否会杀死SaaS”时&#xff0c;销售易已经给出了自己的答案。3月27日&#xff0c;在2026腾讯云城市峰会首站上海站&#xff0c;腾讯旗下CRM销售易正式发布新一代营销服全场景AI原生CRM——NeoAgent 2.0。这并非一次简单的产品迭代&#xff0c;而是销售易…...

网络安全有哪些岗位,如何成为一位优秀的网络安全工程师?

网络安全是什么&#xff1f; 首先说一下什么是网络安全&#xff1f; 网络安全工程师工作内容具体有哪些&#xff1f; 网络安全是确保网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而受到破坏、更改、泄露&#xff0c;系统连续可靠正常地…...

Dramatron:AI驱动的剧本创作革命

Dramatron&#xff1a;AI驱动的剧本创作革命 【免费下载链接】dramatron Dramatron uses large language models to generate coherent scripts and screenplays. 项目地址: https://gitcode.com/gh_mirrors/dr/dramatron 价值定位&#xff1a;重新定义创意写作流程 在…...

AI辅助开发新体验:与快马平台协作迭代,智能生成与优化企业网站代码

AI辅助开发新体验&#xff1a;与快马平台协作迭代&#xff0c;智能生成与优化企业网站代码 最近在帮朋友做一个企业网站项目&#xff0c;尝试了用AI辅助开发的方式&#xff0c;整个过程比想象中顺畅很多。特别是通过InsCode(快马)平台的AI协作功能&#xff0c;从生成初始代码到…...

咱们今天聊点硬核但有趣的东西——用纳米级乐高积木(二氧化钛超表面)玩转光漩涡。想象一下,你手上有把能操控光波前形状的万能钥匙,这就是超表面的魅力所在

FDTD模型:基于超表面的完美涡旋光案例。 宽带任意阶 完美涡旋光束 介绍&#xff1a;全介质超表面实现完美矢量涡旋光束生成和完美庞加莱球生成&#xff0c;完美矢量涡旋光束不随拓扑荷的变化而变化&#xff0c;同时满足矢量光场的偏振变化&#xff0c;主要用于光学加密等领域&a…...

如何快速解锁网易云音乐NCM文件:ncmdumpGUI终极指南

如何快速解锁网易云音乐NCM文件&#xff1a;ncmdumpGUI终极指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 还在为网易云音乐下载的NCM格式文件无法在其他…...