5.2 线程实际案例练习
文章目录
- 1.概述
- 2.实现方案一:继承Thread
- 2.1 代码实现
- 2.2 代码分析
- 3.实现方案二:实现Runnable接口
- 3.1 代码实现
- 3.2 代码分析
- 4.实现方案三:构建线程池
- 4.1 代码实现
- 4.2 代码分析
1.概述
接下来我们通过一个售票案例的实际操作来深入理解线程的相关应用;
需求:设计4个售票窗口,总计售票100张,使用多线程的方式进行售卖,当票售完后,停止售卖,在控制台打印具体为哪个线程售卖了第多少张票;
2.实现方案一:继承Thread
首先,我们通过简单的方法——继承Thread类来实现这一功能;
2.1 代码实现
package partFour;
/*设计多线程编程模型,4个窗口购机售票100张* 本方案使用多线程编程方案1,继承Thread类的方式来完成*/
public class TestThreat {public static void main(String[] args) {//5.创建多个线程对象TicketsThread t1 = new TicketsThread();TicketsThread t2= new TicketsThread();TicketsThread t3 = new TicketsThread();TicketsThread t4 = new TicketsThread();//6.以多线程的方式启动t1.start();t2.start();t3.start();t4.start();}
}
//1.自定义多线程售票类,继承Thread
class TicketsThread extends Thread{//3.定义变量,保存要卖的票数,需要设置静态,不然4个线程对象每个线程对象都会有100张票/*4个线程对象每个线程对象售票400张,原因是创建了4次对象,各自操作各自的成员变量* 解决:让所有对象共享同一个数据,票数需要设置为静态*/static int tickets = 100;//2.重新run方法@Overridepublic void run(){//4.1循环卖票,使用while循环,方便后续演示容易出错的位置while (true){//7.让每个线程经历休眠,增加线程状态切换频率与出错的概率//问题1:产生重卖的现象,同一张票卖给多人//问题2:产生了超卖的现象,超出了规定的票数100,出现了0,-1,-2try {Thread.sleep(10);//让当前线程休眠10ms} catch (InterruptedException e) {e.printStackTrace();}//4.2打印当前正在卖票的线程名称,并且票数-1System.out.println(getName()+"="+tickets--);//4.3做判断,如果没有票了,就退出死循环if (tickets<=0) break;//注意,死循环一定要设置出口}}
}
2.2 代码分析
- 每次创建线程对象,都会生成一个tickets变量值是100,创建4次对象就生成了400张票了。不符合需求,怎么解决呢?
能不能把tickets变量在每个对象间共享,就保证多少个对象都是卖这100张票。
解决方案: 用静态修饰 - 产生超卖,0 张 、-1张、-2张。
- 产生重卖,同一张票卖给多人。
- 多线程安全问题是如何出现的?常见情况是由于线程的随机性+访问延迟。
- 以后如何判断程序有没有线程安全问题?
在多线程程序中 + 有共享数据 + 多条语句操作共享数据就一定会有线程的并发安全问题,就一定考虑如何避免或解决这个问题;
在目前,我们只能考虑使用同步锁解决;
3.实现方案二:实现Runnable接口
接下来,我们将使用更复杂一点的Runnable接口来实现此功能;
3.1 代码实现
package partFour;
/*需求:设计多线程编程模型,4个窗口共计售票100张* 本方案使用多线程编程方案2,实现Runnable接口的方式来完成*/
public class TestRunnable {public static void main(String[] args) {//5.创建Runnable接口的实现类对象,作为目标业务对象TicketsRunnable target = new TicketsRunnable();//6.创建多个Thread类线程对象,并将target业务交给多个线程对象来处理Thread t1 = new Thread(target);Thread t2 = new Thread(target);Thread t3 = new Thread(target);Thread t4 = new Thread(target);//7.以多线程的方式启动多个线程对象t1.start();t2.start();t3.start();t4.start();}
}//1.自定义多线程类实现Runnable接口
class TicketsRunnable implements Runnable{//3.定义一个成员变量,用来保存票数100/*由于自定义类对象只创建了一次,所以票数被所有线程对象Thread共享* 不需要添加static,只卖了100张票,不会卖400次*/int tickets = 100;//2.添加接口中未实现的方法,方法里是我们的业务@Overridepublic void run(){//4.1循环卖票while (true){//8.让每个线程经历休眠,增加线程状态切换频率与出错的概率//问题1:产生重卖的现象,同一张票卖给多人//问题2:产生了超卖的现象,超出了规定的票数100,出现了0,-1,-2try {Thread.sleep(10);//让当前线程休眠10ms} catch (InterruptedException e) {e.printStackTrace();}//4.2打印当前正在售票的线程名称 & 票数-1System.out.println(Thread.currentThread().getName()+"="+tickets--);//4.3设置死循环的出口,没票了就停止卖票if(tickets<=0)break;}}
}
3.2 代码分析
- 实现Runnable接口中,因为只创建了一个对象,所以并不会生成多个tickets变量的值,所以此处我们不需要使用静态来修饰变量
- 同样产生超卖,0 张 、-1张、-2张。
- 同样产生重卖,同一张票卖给多人。
- 同样产生线程的并发安全问题;
4.实现方案三:构建线程池
如果在程序中创建大量的生命周期很短的线程,这会对性能产生比较大的影响,构建一个新的线程还算是一个比较大的开销;
此时,我们可以利用线程池很好的去解决这个问题,这样我们就不必将每个任务都映射到一个单独的线程上了。
线程池中会包含很多准备运行的线程,为线程池提供一个Runnable,就会有一个线程调用run方法,当run方法执行完毕后,线程并不会死亡,而是继续在池中等待下一个请求的调用。
我们通常使用Executors用来辅助创建线程池的工具类,常用的方法是:newFixedThreadPoo(int),这个方法可以帮我们创建指定数目线程的线程池;
4.1 代码实现
package partFour;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/* 本类用于回顾多线程售票案例2*/
public class TestRunnablevPool {public static void main(String[] args) {//1.创建实现类也就是目标业务对象TicktRunnable2 target = new TicktRunnable2();//2.使用Excutors创建最多包含5个线程的线程池--ExcutorService/*Executors是用来辅助创建线程池的工具类* 常用的方法是:newFixedThreadPoo(int)这个方法可以帮我们创建指定书目线程的线程池*/ExecutorService pool = Executors.newFixedThreadPool(5);//3.使用循环,启动线程for(int i=0; i<5; i++){/*execute让线程池中的线程来执行业务* 每次调用这个方法,都会将一个线程加到就绪队列中* 这个方法的参数,就是我们要执行的具体业务,也就是目标业务类对象target*/pool.execute(target);}}
}//1.创建接口实现类,作为目标业务量
class TicktRunnable2 implements Runnable{//3.1定义票数int tickets = 100;//8.注意在外部添加一个唯一的对象,Object o = new Object();//2.添加父接口中未实现的抽象方法,里面是业务@Overridepublic void run() {//3.2循环卖票while (true) {if (tickets>0)//7.为了增加线程状态切换概率与出错频率,在售票前休眠10毫秒try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("窗口" + Thread.currentThread().getName() + "售票" + tickets--);if (tickets <= 0) break;}}
}
4.2 代码分析
- 通过构建线程池可以很好的解决资源浪费的问题
- 虽然使用了双重校验,但还是存在超卖,重卖的问题
相关文章:
5.2 线程实际案例练习
文章目录1.概述2.实现方案一:继承Thread2.1 代码实现2.2 代码分析3.实现方案二:实现Runnable接口3.1 代码实现3.2 代码分析4.实现方案三:构建线程池4.1 代码实现4.2 代码分析1.概述 接下来我们通过一个售票案例的实际操作来深入理解线程的相…...
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
文章目录一、STM32串口常用寄存器和库函数1.1 常用的串口寄存器1.2 串口相关的库函数1.3 状态寄存器(USART_ SR)1.4 数据寄存器(USART_ DR)1.5 波特率寄存器(USART_BRR)二、串口配置一般步骤一、STM32串口常…...
山西省2023年软考报名3月14日开始
根据2023年上半年计算机技术与软件专业技术资格(水平)考试工作计划,可以得知,全国考务管理服务平台将于2023年3月13日开放,各地开始组织报名,如山西已发布2023上半年报名简章,从3月14号开始报名。 软考报名官网 大部…...
进程章节总结性实验
进程实验课笔记 本节需要有linux基础,懂基本的linux命令操作即可。 Ubuntu镜像下载 https://note.youdao.com/s/VxvU3eVC ubuntu安装 https://www.bilibili.com/video/BV1j44y1S7c2/?spm_id_from333.999.0.0 实验环境ubuntu22版本,那个linux环境都可以…...
【MyBatis】MyBatis的缓存
10、MyBatis的缓存 10.1、MyBatis的一级缓存 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问 使一级缓存失效的四种情况: 不…...
MyBatis基本使用
一、简介 MyBatis 中文文档 https://mybatis.org/mybatis-3/zh/index.html 1.什么是 MyBatis 概述:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBa…...
如何运行YOLOv6的代码实现目标识别?
YOLOv6是由美团视觉团队开发的1.环境配置我们先把YOLOv6的代码clone下来git clone https://github.com/meituan/YOLOv6.git安装一些必要的包pip install pycocotools2.0作者要求pytorch的版本是1.8.0,我的环境是1.7.0,也是可以正常运行的pip install -r requirement…...
新品BCM6755A1KFEBG/MT7921LE/MT7921AU WiFi芯片
博通在WiFi市场具有相当的实力。在WiFi6上有下面这几个解决方案:型号:BCM6755 BCM6755A1KFEBG类型:四核1.5GHz CPU封装:BGA批次:新BCM6755和BCM6750还是A7架构,更多的用在中低端型号上。BCM6755和BCM6750 C…...
析构函数、拷贝构造
1、析构函数析构函数的定义方式函数名和类名相同,在类名前加~,没有返回值类型,没有函数形参(不能重载)当对象生命周期结束的时候,系统会自动调用析构函数先调用析构函数,再释放对象的空间析构函…...
光学镜头是制作过程阶段理解
光学镜头是由多组镜片组合而成,它是摄影机投影一及显微镜上必不可少的部件。那么光学镜头是如何制造的呢?光学镜头的制作分为以下四个阶段:第一、首先将一大块光学玻璃用钻石锯片进行切片,然后用钻头在每一块玻璃切片上钻出多块冰…...
实验室设计|实验室设计要点SICOLAB
一、实验室设计规划要素1、实验室布局:实验室的布局要符合实验室工作流程,可以将实验室划分为干净区和污染区,以确保实验室的卫生和实验的准确性。2、设备选购:根据实验需要选择适当的设备,并确保设备的质量和性能符合…...
I.MX6ULL_Linux_系统篇(16) uboot分析-启动流程
原文链接:I.MX6ULL_系统篇(16) uboot分析-启动流程 – WSY Personal Blog (cpolar.cn) 前面我们详细的分析了 uboot 的顶层 Makefile,了解了 uboot 的编译流程。本章我们来详细的分析一下 uboot 的启动流程,理清 uboot 是如何启动的。通过对 …...
【C#】async关键字修饰后有无await的影响
文章目录测试总结拓展:js的async await问题参考测试 来自微软官网的说法: 异步方法通常包含 await 运算符的一个或多个匹配项,但缺少 await 表达式不会导致编译器错误。 如果异步方法未使用 await 运算符标记悬挂点,则该方法将作…...
Interspeech2022 | 一种基于元辅助学习的低资源口语语义理解方法
中国移动研究院首席科学家冯俊兰博士带领人工智能与智慧运营中心语音团队共同撰写的文章《Meta Auxiliary Learning for Low-resource Spoken Language Understanding》被语音国际顶会Interspeech2022接收。 关于Interspeech Interspeech 是国际最大且最全面关于言语科学与技…...
File类的用法和InputStream,OutputStream的用法
这里写自定义目录标题一、File类1.构造方法2.普通方法二、InputStream1.方法2.FileInputStream3.Scanner类的应用三、OutputStream1.方法2.FileOutputStream3.PrintWriter类的应用一、File类 1.构造方法 签名说明File(File parent, Stringchild)根据父目录 孩子文件路径&…...
Java多线程——Thread类的基本用法
一.线程的创建继承Thread类//继承Thread类class MyThread extends Thread{Overridepublic void run() {System.out.println("线程运行的代码");} } public class Demo1 {public static void main(String[] args) {MyThread t new MyThread();t.start();//启动线程&a…...
【C++】类和对象练习——日期类的实现
文章目录前言1. 日期的合法性判断2. 日期天数(/)2.1 和的重载2.2 对于两者复用的讨论3. 前置和后置重载4. 日期-天数(-/-)5. 前置- -和后置- -的重载6. 日期-日期7. 流插入<<重载8. 流提取>>重载9. 总结10. 源码展示前…...
[LeetCode周赛复盘] 第 333 场周赛20230219
[LeetCode周赛复盘] 第 333 场周赛20230219 一、本周周赛总结二、 [Easy] 6362. 合并两个二维数组 - 求和法1. 题目描述2. 思路分析3. 代码实现三、[Medium] 6365. 将整数减少到零需要的最少操作数1. 题目描述2. 思路分析3. 代码实现四、[Medium] 6364. 无平方子集计数1. 题目描…...
数字化时代,如何做好用户体验与应用性能管理
引言 随着数字化时代的到来,各个行业的应用系统从传统私有化部署逐渐转向公有云、行业云、微服务,这种变迁给运维部门和应用部门均带来了较大的挑战。基于当前企业 IT 运维均为多部门负责,且使用多种运维工具,因此,当…...
Python爬虫(7)selenium3种弹窗定位后点击操作,解决点击登录被隐藏iframe无法点击的登陆问题
之前的文章有关于更多操作方式详细解答,本篇基于前面的知识点进行操作,如果不了解可以先看之前的文章 Python爬虫(1)一次性搞定Selenium(新版)8种find_element元素定位方式 Python爬虫(2)-Selenium控制浏览…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
