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

【Java EE初阶 --- 多线程(初阶)】多线程的实现案例

乐观学习,乐观生活,才能不断前进啊!!!

我的主页:optimistic_chen

我的专栏:c语言 ,Java

欢迎大家访问~
创作不易,大佬们点赞鼓励下吧~

文章目录

  • 前言
  • 单例模式
    • 实现单例模式
      • 饿汉模式·
      • 懒汉模式
  • 阻塞队列
    • 生产者消费者模型
    • 标准库中的阻塞队列
  • 模拟实现阻塞队列(生产者消费者模型)
  • 线程池
    • 为什么从线程池去线程更高效?
    • 标准库中的线程池
    • 实现线程池
  • 完结

前言

之前博客对多线程的是什么和基本内容都有详细了解,目前对于多线程的运用还很浅显,不能发挥出多线程应有的实力。这篇博客将带来多线程的基本应用,它会用到什么地方?又会带来什么高效的运行效率?我们又会学到什么?诸位尽情期待…

单例模式

单例模式是设计模式之一
两个新名词,什么是设计模式?什么又是单例模式呢?

设计模式相当于棋谱是行业内大佬为新人撰写的一些高效便捷的思路和案例。棋手除了不断下棋提高实力外,就是尽可能多的研读棋谱,解决问题;而对于程序员来讲,设计模式就是棋手的棋谱,面对一些棘手的问题时,设计模式就是我们的制胜法宝,更加重要的是,设计模式可以大大减少程序员代码风格的不同(因为大家都是根据“棋谱”解决问题)

而单例模式就是众多“棋谱”中的一种,保证某个类在程序中只存在唯⼀⼀份实例(对象), ⽽不会创建出多个实例(只能new一个对象)

实现单例模式

单例模式的实现方式很多,最常见的就是”饿汉”和“懒汉“两种:主要区别就是创建对象的时机:创建对象早,就是饿汉模式(懂得都懂);反之,创建对象迟,就是懒汉模式。

这里一个关键是:构造方法设为 private(使单例模式生效)

饿汉模式·

在初始化(类加载)的时候就new好对象(提早)

class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {//获取实例return instance;//读操作}
}

实例提前创建过,就不涉及线程安全问题,只是一个单纯的读操作。

懒汉模式

使用时再 new 对象(能不创建就不创建)

class Singleton {private static volatile Singleton instance = null;Object locker=new Object();private Singleton() {}public static Singleton getInstance() {//获取实例if (instance == null) {synchronized (locker) {if (instance == null) {//当instance为空,创建实例instance = new Singleton();}}}return instance;}
}

在这里插入图片描述

阻塞队列

阻塞队列能是⼀种线程安全的数据结构,也遵守“先进先出”的基本原则,并且具有以下特性:
• 天然线程安全
• 当队列满的时候, 继续⼊队列就会阻塞, 直到有其他线程从队列中取⾛元素.
• 当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插⼊元素.

最主要的应用场合是 生产者消费者模型

生产者消费者模型

<举个例子> 过年包饺子,我负责擀饺子皮,妈妈和爸爸负责包饺子,持续一段时间后,整个工作结束。整个场景的资源是“饺子皮”,我是“生产者”,爸爸妈妈是“消费者”,这个场景就是“阻塞队列”

生产者消费者模型的优势:

  1. 解耦合
    在这里插入图片描述
  2. 削峰填谷
    在这里插入图片描述

生产者消费者模型要付出的代价:
1. 整体结果趋于复杂化,需要更多机器,生产环境难以管理
2. 影响效率

标准库中的阻塞队列

public interface BlockingQueue<E> extends Queue<E>{
}

BlockingQueue 是⼀个接⼝.所以不能直接去new, 其真正实现的类是 LinkedBlockingQueue.
在这里插入图片描述
本来,队列入队和出队操作是offer和poll,但是我们这里是多线程情况,得使用带有阻塞功能的put和take。

比如:当队列为空时,却被take时,就会出现阻塞
在这里插入图片描述
这是完美运行的生产者消费者模型:

 public static void main(String[] args) throws InterruptedException {BlockingQueue<Integer> queue=new LinkedBlockingQueue<>(1000);Thread producer=new Thread(()->{int n=0;while(true){try {queue.put(n);n++;System.out.println("生产元素"+n);} catch (InterruptedException e) {e.printStackTrace();}}},"producer");Thread consumer=new Thread(()->{while(true){try {Integer n=queue.take();System.out.println("消费元素"+n);} catch (InterruptedException e) {e.printStackTrace();}}},"consumer");producer.start();consumer.start();}

在这里插入图片描述

模拟实现阻塞队列(生产者消费者模型)

import java.util.concurrent.BlockingQueue;class MyBlockQueue{private String[] data=null;private int head;private int tail;private int size;public MyBlockQueue(int capacity){data=new String[capacity];}public void put(String elem) throws InterruptedException {synchronized (this){while(size>=data.length){//队列满了,阻塞this.wait();//此时阻塞,当队列不满时,唤醒}data[tail]=elem;tail++;if(tail>=data.length){tail=0;}size++;this.notify();}}public String take() throws InterruptedException {synchronized (this){while(size==0){//while二次判定队列是否为空//队列为空,阻塞this.wait();//队列不空时,唤醒}String ret=data[head];head++;if(head>=data.length){head=0;}size--;this.notify();return ret;}}
}public class Demo12 {public static void main(String[] args) {MyBlockQueue queue=new MyBlockQueue(1000);Thread producer=new Thread(()->{int n=0;while(true){try {queue.put(n+"");n++;System.out.println("生产元素"+n);} catch (InterruptedException e) {e.printStackTrace();}}},"producer");Thread consumer=new Thread(()->{while(true){try {String  n=queue.take();System.out.println("消费元素"+n);} catch (InterruptedException e) {e.printStackTrace();}}},"consumer");producer.start();consumer.start();}
}

线程池

对比常量池来看,字符串常量,在Java程序运行最初的时候就构建好了,等程序运行的时候,这些常量就加载到内存中;后续使用这些字符串时,直接从内存中获取,避免了字符串构造/销毁的开销。
线程池也是这样,提前创建好要使用的线程,以后要用的时候就能减少每次创建、销毁线程的损耗,提高性能。

<举个例子>其实大家可以带入“鱼塘”,想吃鱼了,捞一条上来。鱼塘里很多鱼,减少了外出购买的时间,是不是降低了损耗...

为什么从线程池去线程更高效?

首先,一个操作系统是它的内核与配套的应用程序组成。内核给应用程序提供稳定的运行环境,同时管理硬件设备。
创建线程需要操作系统内核的配合,但是内核只有一个,如果同时出现多个要求创建线程的需求,这个时候还能保证高效吗?但是如果从线程池中取现成的线程,就不需要内核的参与,就不会出现“拥挤”的情况

<举个例子>使用线程池就是去银行ATM机上取钱,创建线程是去银行柜台取钱。生活中,我们都知道ATM的效率高。

所以,使用线程池就可以省下应用程序切换到内核运行这样的消耗。

标准库中的线程池

核心方法:submit(Runnable)
通过Runnnable描述一段要执行的任务,通过submit把任务放到线程池中,此时线程池里的线程就会执行任务。本质上还是生产者消费者模型,submit在生产任务,线程池在消费任务。
在这里插入图片描述

构造这个类时,构造方法比较复杂,它的参数特别多…
主要看参数最多的构造方法,掌握整个其他的也就拿下了。

在这里插入图片描述

BlockingQueue workQueue:线程池允许我们程序员自己传一个工作队列,这可操作性就很高,我们可自主选择队列的基本参数,包括它的底层实现。
ThreadFactory threadFactory:创建线程的工厂,设计模式的一种,和前面的单例模式属于并列关系。为了统一构造并初始化线程。
在这里插入图片描述

工厂方法的核心:通过静态方法,把构造对象new的过程、各种初始化的过程,都封装为一个方法;提供多组静态方法,实现不同情况的构造。提供工厂方法的类就是工厂类。
在这里插入图片描述

RejectedExecutionHandler handler:拒绝策略,入队时,队列满了,不会真的造成阻塞(拒绝等待),而是执行下面拒绝策略的代码(提高效率)
在这里插入图片描述

实现线程池

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;class MyThreadPool{private BlockingQueue<Runnable> queue=new LinkedBlockingQueue<>();public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}public MyThreadPool(int n){for(int i = 0; i<n; i++){Thread t=new Thread(()->{while(true){try {Runnable runnable=queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}
}public class Demo14 {public static void main(String[] args) throws InterruptedException {MyThreadPool pool=new MyThreadPool(4);for(int i=0;i<100;i++){pool.submit(()->{System.out.println("hello "+Thread.currentThread().getName());});}}
}

完结


可以点一个免费的赞并收藏起来~
可以点点关注,避免找不到我~ ,我的主页:optimistic_chen
我们下期不见不散 ~ ~ ~

相关文章:

【Java EE初阶 --- 多线程(初阶)】多线程的实现案例

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 前言单例模式实现单例模式…...

制作一款打飞机游戏64:关卡设计

今天我想完成第一个音乐循环的关卡设计。 初始设置 首先&#xff0c;我要删除所有之前创建的敌人和“大脑”&#xff08;可能指敌人的行为模式或AI&#xff09;。我不想保留它们&#xff0c;我要从零开始&#xff0c;重新创建敌人。但我会保留精灵&#xff08;游戏中的角色或…...

开发常用的QT mql组件

Column Column 是一种将其子项沿单个列定位的类型。它是不使用锚点的情况下垂直定位一系列项目的便捷方式。 add : Transition bottomPadding : real leftPadding : real move : Transition padding : real populate : Transition rightPadding : real spacing : rea…...

Git操作记录

一.简单上传操作 1.Git 全局设置 git config --global user.name "xxx" git config --global user.email "xxx"2.创建新存储库 git clone gitgitlab.xxx.cn:xx/xxx/xxx.git cd test touch README.md git add README.md git commit -m "add README&qu…...

Vue Router的核心实现原理深度解析

1. Vue Router的基本架构 Vue Router的核心功能是实现前端路由&#xff0c;即在不重新加载页面的情况下更改应用的视图。它的基本架构包括&#xff1a; 路由配置&#xff1a;定义路径与组件的映射关系路由实例&#xff1a;管理路由状态和提供导航方法路由视图&#xff1a;渲染…...

Python趣学篇:用Pygame打造绚烂流星雨动画

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 专栏介绍&#xff1a;《Python星球日记》 目录 一、项目简介与效果展示二、技术栈与核…...

AI系统负载均衡与动态路由

载均衡与动态路由 在微服务架构中,负载均衡是实现服务高可用和性能优化的关键机制。传统负载均衡技术通常围绕请求数、连接数、CPU占用率等基础指标进行分发,而在AI系统中,特别是多模型、多异构算力(如CPU、GPU、TPU)共存的环境下,负载均衡不仅要考虑节点资源消耗,还需…...

山西省第十八届职业院校技能大赛 网络建设与运维赛项 样题

山西省第十八届职业院校技能大赛 网络建设与运维赛项 &#xff08;学生组&#xff09; 样题 2024 年 11 月 xx 日 2 赛题说明 一、竞赛项目简介 “网络建设与运维”竞赛共分为模块一&#xff1a;网络理论测试与网络 运维&#xff1b;模块二&#xff1a; 网络建设与调试&a…...

Stone 3D新版本发布,添加玩家控制和生物模拟等组件,增强路径编辑功能,优化材质编辑

后续版本号改为构建日期加小版本&#xff0c;所以最新版本为20250603.01 功能更新如下&#xff1a; 1. 改写fps-controls组件&#xff0c;简化游戏应用的创建&#xff0c;你只需要一个场景glb&#xff0c;然后给Scene节点添加fps-controls组件&#xff0c;即可完成一个第一人…...

【Qt】之【Get√】【Bug】通过值捕获(或 const 引用捕获)传进 lambda,会默认复制成 const

通过值捕获&#xff08;或 const 引用捕获&#xff09;传进 lambda&#xff0c;会默认复制成 const。 背景 匿名函数外部定义 QSet<QString> nameSet,需要传入匿名函数使用修改 connect(dlg, ..., [nameSet](...) {nameSet.insert(name); // ❌ 这里其实是 const QSet…...

排序算法C语言实现

算法概览 排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景插入排序O(n)O(n)O(1)稳定小规模/基本有序希尔排序O(n log n)O(n)O(1)不稳定中等规模冒泡排序O(n)O(n)O(1)稳定教学/小规模堆排序O(n log n)O(n log n)O(1)不稳定大规模数据选择排序O(n)O(n)O(1)不稳定…...

Python----目标检测(训练YOLOV8网络)

一、数据集标注 在已经采集的数据中&#xff0c;使用labelImg进行数据集标注&#xff0c;标注后的txt与原始 图像文件同名且在同一个文件夹&#xff08;data&#xff09;即可。 二、制作数据集 在data目录的同目录下&#xff0c;新建dataset目录&#xff0c;以存放制作好的YOLO…...

构建 MCP 服务器:第一部分 — 资源入门

什么是模型上下文协议? 模型上下文协议(MCP) 是Claude等大型语言模型 (LLM) 与外部数据和功能安全交互的标准化方式。您可以将其想象成一个平视显示器,或者 AI 的 USB 端口——它提供了一个通用接口,允许任何兼容 MCP 的 LLM 连接到您的数据和工具。 MCP 提供了一个集中式协…...

c# :this() 和 :base()区别

在 C# 中&#xff0c;:this() 和 :base() 都用于构造函数的重载和继承&#xff0c;但它们有不同的用途和上下文&#xff1a; 1. :this() 用途&#xff1a;用于调用当前类中的其他构造函数&#xff08;构造函数重载&#xff09;。场景&#xff1a;当你希望一个构造函数先执行另…...

使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第十五讲)

这一期讲解lvgl中日历控件的基础使用&#xff0c;Calendar 部件是一个经典日历&#xff0c;它具有以下功能&#xff1a;• 通过一个7x7矩阵显示任何月份 • 显示日期名称 • 突出显示当前日期&#xff08;今天&#xff09; • 突出显示任何用户定义的日期 日历是一个可编辑的小…...

Vue中实现表格吸底滚动条效果,列太多时左右滚动条始终显示在页面中

1、安装 npm install el-table-horizontal-scroll 2、全局注册&#xff08;main.js&#xff09; import horizontalScroll from el-table-horizontal-scrollVue.use(horizontalScroll) 如下图&#xff0c;在main.js加上上面的代码 3、表格内引用 <el-table :data"…...

BeeWorks 协同办公能力:局域网内企业级协作的全场景重构

在企业数字化办公场景中&#xff0c;BeeWorks 以强大的协同办公能力&#xff0c;将局域网内的通讯、协作、业务流程整合为统一整体。作为专注于企业级局域网环境的协作平台&#xff0c;其不仅提供即时通讯基础功能&#xff0c;更通过办公工具集成、会议能力强化、业务系统对接等…...

Mermaid 绘图--以企业权限视图为例

文章目录 一、示例代码二、基础结构设计2.1 组织架构树2.2 权限视图设计 三、销售数据权限系统四、关键语法技巧汇总 一、示例代码 在企业管理系统开发中&#xff0c;清晰的权限视图设计至关重要。本文将分享如何使用 Mermaid 绘制直观的企业权限关系图&#xff0c;复制以下代…...

Redis(02)Win系统如何将Redis配置为开机自启的服务

一、引言 Redis 是一款高性能的键值对存储数据库&#xff0c;在众多项目中被广泛应用。在 Windows 环境下&#xff0c;为了让 Redis 能更稳定、便捷地运行&#xff0c;将其设置为系统服务并实现自动启动是很有必要的。这样一来&#xff0c;系统开机时 Redis 可自动加载&#xf…...

C++课设:高效的日程管理系统

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 专栏介绍&#xff1a;《编程项目实战》 目录 一、C日程管理系统的时代价值1. 为什么选…...

功能测试、性能测试、安全测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、功能测试 1、单接口功能 手工测试中的单个业务模块&#xff0c;一般对应一个接口 例如&#xff1a; 登录业务------登录接口 加入购物车业务------加入购…...

提示词指南 --- 提示词的基本结构

提示词指南 --- 提示词的基本结构以及三种角色 什么是Prompt (提示词)Prompt的基本结构和三种角色提示词的三种核心“角色”&#xff08;Role&#xff09; 真实例子 什么是Prompt (提示词) 我们可以把“Prompt&#xff08;提示词&#xff09;”想象成和AI聊天时你说的“一句话…...

UI学习—cell的复用和自定义cell

前言 Nib是什么&#xff1f; Nib就是.xib文件&#xff1a;一个可视化的UI界面文件&#xff0c;它记录了一个UI组件&#xff08;例如一个表格单元格Cell&#xff09;的界面布局信息&#xff0c;可以在interfaceBuilder中创建 [UINib nibWithNibName:"CustomCell" b…...

20250605使用boot-repair来恢复WIN10和ubuntu22.04.6双系统的启动

rootrootrootroot-X99-Turbo:~$ sudo apt-get install boot-repair rootrootrootroot-X99-Turbo:~$ sudo add-apt-repository ppa:yannubuntu/boot-repair rootrootrootroot-X99-Turbo:~$ sudo apt-get install boot-repair 20250605使用boot-repair来恢复WIN10和ubuntu22.04.6…...

网络安全面试题目(无答案)

一、渗透测试与漏洞挖掘 如何绕过WAF进行SQL注入&#xff1f;列举三种技术并解释原理。 答案要点&#xff1a; 分块传输编码&#xff08;Chunked Transfer&#xff09;绕过正则检测 畸形HTTP参数&#xff08;如参数污染、Unicode编码&#xff09; 利用WAF规则盲区&#xff08…...

JavaScript性能优化实战

### 1. 减少全局变量 JavaScript里&#xff0c;全局变量就像一个大杂烩&#xff0c;啥都往里扔&#xff0c;很容易出问题&#xff0c;还会影响性能。为啥呢&#xff1f;因为全局变量会被所有函数共享&#xff0c;查找起来特别费劲&#xff0c;就像在一个大仓库里找东西&#xf…...

接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

1 、 API 分类特征 SOAP - WSDL OpenApi - Swagger RESTful - /v1/api/ 2 、 API 常见漏洞 OWASP API Security TOP 10 2023 3 、 API 检测流程 接口发现&#xff0c;遵循分类&#xff0c;依赖语言&#xff0c; V1/V2 多版本等 Method &#xff1a;请求方法 攻击方…...

视频汇聚平台EasyCVR“明厨亮灶”方案筑牢旅游景区餐饮安全品质防线

一、背景分析​ 1&#xff09;政策监管刚性需求​&#xff1a;国家食品安全战略及 2024年《关于深化智慧城市发展的指导意见》要求构建智慧餐饮场景&#xff0c;推动数字化监管。多地将“AI明厨亮灶”纳入十四五规划考核&#xff0c;要求餐饮单位操作可视化并具备风险预警能力…...

sql server如何创建表导入excel的数据

在 SQL Server 中&#xff0c;可以通过几种方式将 Excel 数据导入到数据库表中。下面是一个完整的流程&#xff0c;包括如何创建表&#xff0c;以及将 Excel 数据导入该表的方法&#xff1a; ✅ 方法一&#xff1a;使用 SQL Server Management Studio (SSMS) 的导入向导&#x…...

仓库自动化搬运:自动叉车与AGV选型要点及核心技术解析

自动叉车与AGV均可实现自主作业&#xff0c;无需人工驾驶即可搬运托盘化货物。然而&#xff0c;这两种解决方案存在一些关键差异。 自动叉车与AGV的对比 自动叉车与AGV是截然不同的车辆&#xff0c;其差异主要源于原始设计&#xff1a; 自动叉车是制造商对传统手动叉车进行改…...