多线程合并练习题,线程安全(售票任务引入)--学习JavaEE的day30

day30

练习(day29)

注意代码注释,里面涉及代码实现遇到问题及解决方案,由于理解方便没有单独出来

1.计算任务

1.计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。

使用线程类

public class MyThread extends Thread{private int startIndex;//开始下标(包含)private int endIndex;//结束下标(不包含)private int[] arr;//外界数组public MyThread(int startIndex, int endIndex, int[] arr) {this.startIndex = startIndex;this.endIndex = endIndex;this.arr = arr;}private int sum;private boolean flag = true;@Overridepublic void run() {for (int i = startIndex; i < endIndex; i++) {sum += arr[i];}flag = false;}public int getSum() {return sum;}public boolean isFlag() {return flag;}
}
public class Test01 {public static void main(String[] args) throws InterruptedException {//创建数组int[] arr = new int[20000];//初始化数组数据 -- {1,2,3,....,20000}for (int i = 0; i < arr.length; i++) {arr[i] = i+1;}//创建线程MyThread t1 = new MyThread(0, 5000, arr);MyThread t2 = new MyThread(5000, 10000, arr);MyThread t3 = new MyThread(10000, 15000, arr);MyThread t4 = new MyThread(15000, 20000, arr);//启动线程t1.start();t2.start();t3.start();t4.start();//问题出现原因:四个子线程还没有运行完毕,就被主线程抢到CPU资源了//解决思路:让四个子线程执行完毕后,主线程才能执行 --- 主线程阻塞!!!//解决方案一:休眠电脑算完后,就能得到准确的结果;(主线程阻塞,拿不到cpu资源)
//		Thread.sleep(6);//解决方案二:判断子线程是否执行完,有一个没执行完,主线程都不会输出;(主线程可以拿到cpu资源)
//		while(t1.isFlag() || t2.isFlag() || t3.isFlag() || t4.isFlag()){}//解决方案三:子线程join,主线程阻塞,四个子线程执行完毕,主线程才抢到cpu资源(方案2缺点:主线程未阻塞)t1.join();t2.join();t3.join();t4.join();//合并子线程的运行结果int result = t1.getSum() + t2.getSum() + t3.getSum() + t4.getSum();System.out.println(result);}
}

对于解决方案二:开始添加下面注释部分代码,即判断线程是否执行完毕的变量,和相关变量get方法

//	private boolean flag = true;@Overridepublic void run() {for (int i = startIndex; i < endIndex; i++) {sum += arr[i];}//		flag = false;}//	public int getSum() {
//		return sum;
//	}//	public boolean isFlag() {
//		return flag;
//	}

使用任务类

任务类更容易理解,线程合并,分拆了多个线程来进行并行计算,2万个整数分成几段

​ //创建任务
​ Task task1 = new Task(0, 5000, arr);
​ Task task2 = new Task(5000, 10000, arr);
​ Task task3 = new Task(10000, 15000, arr);
​ Task task4 = new Task(15000, 20000, arr);

public class Task implements Runnable{private int startIndex;private int endIndex;private int[] arr;public Task(int startIndex, int endIndex, int[] arr) {this.startIndex = startIndex;this.endIndex = endIndex;this.arr = arr;}private int sum;private boolean flag = true;@Overridepublic void run() {for (int i = startIndex; i < endIndex; i++) {sum += arr[i];}flag = false;}public int getSum() {return sum;}public boolean isFlag() {return flag;}}public class Test01 {public static void main(String[] args) throws InterruptedException {//创建数组int[] arr = new int[20000];//初始化数组数据 -- {1,2,3,....,20000}for (int i = 0; i < arr.length; i++) {arr[i] = i+1;}//创建任务Task task1 = new Task(0, 5000, arr);Task task2 = new Task(5000, 10000, arr);Task task3 = new Task(10000, 15000, arr);Task task4 = new Task(15000, 20000, arr);//创建线程Thread t1 = new Thread(task1);Thread t2 = new Thread(task2);Thread t3 = new Thread(task3);Thread t4 = new Thread(task4);//启动线程t1.start();t2.start();t3.start();t4.start();//问题出现原因:四个子线程还没有运行完毕,就被主线程抢到CPU资源了//解决思路:让四个子线程执行完毕后,主线程才能执行 --- 主线程阻塞!!!//解决方案一:
//		Thread.sleep(6);缺点:休眠不知道设置多少好//解决方案二:
//		while(task1.isFlag() || task2.isFlag() || task3.isFlag() || task4.isFlag()){}
//		缺点:主线程会抢到资源,只是条件原因而不会结束//解决方案三:t1.join();t2.join();t3.join();t4.join();//合并任务的运行结果int result = task1.getSum() + task2.getSum() + task3.getSum() + task4.getSum();System.out.println(result);}
}

注意:

主线程结束,子线程还会继续执行完成

2.售票任务(线程安全)

2.铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售,请编写多线程程序来模拟这个效果(该题涉及到线程安全,https://www.jb51.net/article/221008.htm)

i. 窗口001正在销售第1张票

ii. 窗口001正在销售第2张票

iii. 窗口002正在销售第3张票

iv. 。。。

v. 窗口002正在销售第1000张票

涉及到线程安全,要加锁

使用线程类

public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Object obj = new Object();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){//synchronized (String.class) {//synchronized ("abc") {synchronized (obj) {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}}}}
}public class Test01 {public static void main(String[] args) {MyThread t1 = new MyThread("001");MyThread t2 = new MyThread("002");MyThread t3 = new MyThread("003");t1.start();t2.start();t3.start();}
}
模拟过程出现问题
问题一:

三个窗口各卖1000张票,一共卖了3000张

出现原因:allTicket和curTicket是run方法的局部变量,三个线程抢到CPU资源后,都会调用run方法,run方法被调用了3次,所以卖了3000张票

解决方案:将allTicket和curTicket设置为静态变量,让三个线程共享

出现原因:
public class MyThread extends Thread{public MyThread(String name) {super(name);}@Overridepublic void run() {int allTicket = 1000;int curTicket = 0;while(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}
}
解决方案:
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}
}
问题二:

有些票没有卖,有些票卖了重票

出现原因:当前线程抢到CPU资源后做了票的自增,但是还没来得及输出,时间片到了就退出CPU资源,然后其他线程抢到CPU资源了

解决方案:当前线程抢到CPU资源后,票的自增和输出执行完毕才能切换到其他线程运行 – 加锁

出现原因
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;public MyThread(String name) {super(name);}@Overridepublic void run() {
//		  举例:
//        curTicket - 0 -1-2-3....while(curTicket < allTicket){
//			线程t1抢到资源,调用run(),curTicket++变成1,还没来得及输出,时间片到了,退出cpu资源
//          线程t3抢到资源,调用run(),curTicket++变成2,还没来得及输出,时间片到了,退出cpu资源
//          线程t2抢到资源,调用run(),curTicket++变成3,输出正在销售第3张,时间片到了,退出cpu资源
//          线程t1抢到资源,输出正在销售第3张票,时间片到了,退出cpu资源
//          线程t3抢到资源,输出正在销售第3张票,时间片到了,退出cpu资源  curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}
}
解决方案
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;
//	private Object obj = new Object();第三种new(锁)对象
//	注意:成员变量时,new了三次,三个对象,三把锁,没有锁住
//    	设置成静态的,设置成静态变成一把锁(对象)才锁的住private static Object obj = new Object();public MyThread(String name) {super(name);}@Overridepublic void run() {
//		  举例:
//        curTicket - 0 -1-2-3....while(curTicket < allTicket){//第一种:synchronized (String.class) {任意类的对象在程序中唯一的//第二种:synchronized ("abc") {字符串对象放在常量池也是唯一的synchronized (obj) {//自动上锁//			线程t1抢到资源,调用run(),自动上锁,curTicket++变成1,还没来得及输出,时间片到了,退出cpu资源
//          线程t3抢到资源,调用run(),有锁,退出
//          线程t2抢到资源,调用run(),有锁,退出
//          线程t1抢到资源,输出正在销售第3张票,自动解锁,时间片到了,退出cpu资源
//          线程t3抢到资源...curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}//自动解锁}}
}
问题三:

多卖了票

出现原因:curTicket到了临界点(999),三个线程都可以进判断,然后上锁

解决方案:在锁中再次判断

出现原因:
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Object obj = new Object();public MyThread(String name) {super(name);}@Overridepublic void run() {
//		  临界值:
//        curTicket - 999while(curTicket < allTicket){synchronized (obj) {//自动上锁//			线程t1抢到资源,调用run(),还没有上锁,挂起
//          线程t3抢到资源,调用run(),还没有上锁,挂起
//          线程t2抢到资源,调用run(),上锁,curTicket++变成1000,输出正在销售第1000张,时间片到了,退出cpu资源
//          线程t1抢到资源,调用run(),上锁,curTicket++变成1001,输出正在销售第1001张,时间片到了,退出cpu资源
//          线程t3抢到资源,调用run(),上锁,curTicket++变成1002,输出正在销售第1002张,时间片到了,退出cpu资源curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}//自动解锁}}
}
解决方案:
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Object obj = new Object();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){synchronized (obj) {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){//在锁中再次判断System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}}}}
}

注意:

编译字节码命令:javap -verbose MyThread.class(后面会涉及)

监视器开始上锁到解锁
线程安全上锁

锁()new的对象,锁不住是几个对象,需要设置成静态变成一个才锁的住

单线程无锁,多线程会上锁(加的何种锁应情况变化,无锁-偏向锁-轻量级锁-重量级锁-状态标记)

了解内容:感兴趣搜索相关博客等等了解即可

简单来说就是:几个线程就无锁升级到偏向锁,可再变到无锁;有线程数量多了,就会升级到轻量级锁,再多就又升级重量级锁,对于后面加锁就相当给他个互斥状态,注意升级到轻量级锁、重量级锁就降不下去

java对象在内存中的结构,java对象内存分析
简单理解对象内存结构
其中当实例变量达条件,对齐填充就会相应变化
理解对象内存结构

线程安全 – 加锁

注意:要想多个线程互斥住,就必须使用同一把锁(对象)!!!

加锁的方式:

1.synchronized

同步代码块:

synchronized(锁对象){//自动上锁

…想要互斥的代码…

}//自动解锁

2.Lock

总结

1.练习1线程合并(线程类、任务类)

2.买票的案例 – 线程安全 (重要)

3.理解对象内存结构 - https://blog.csdn.net/weixin_44606481/article/details/134802419

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL三种开窗函数详细用法,图文详解

开窗函数的详细用法 第一章、开窗函数的语法1.1&#xff09;从聚合开窗函数讲起1.2&#xff09;开窗函数之取值1.3&#xff09;排名开窗函数 第一章、开窗函数的语法 开窗函数的语法为&#xff1a;over(partition by 列名1 order by 列名2 )&#xff0c;括号中的两个关键词par…

加速新能源汽车产品迭代:融合前沿科技的重要性

新能源汽车新质生产力提升咨询方案 一、新能源汽车企业行业目前发展现状及特点&#xff1a; 1、快速增长 2、技术迭代快 3、竞争加剧 二、新能源汽车企业发展新质生产力面临的痛点&#xff1a; 1、技术创新压力巨大 2、市场竞争激烈 3、供应链稳定性欠缺 4、成本控制压…

微信小程序实战:无痛集成腾讯地图服务

在移动互联网时代,地图服务无疑是应用程序中最常见也最实用的功能之一。无论是导航定位、附近搜索还是路线规划,地图服务都能为用户提供极大的便利。在微信小程序开发中,我们可以轻松集成腾讯地图服务,为小程序赋能增值体验。本文将详细介绍如何在微信小程序中集成使用腾讯地图…

jmeter中参数加密

加密接口常用的方式有&#xff1a; MD5&#xff0c;SHA&#xff0c;HmacSHA RSA AES&#xff0c;DES&#xff0c;Base64 压测中有些参数需要进行加密&#xff0c;加密方式已接口文档为主。 MD5加密 比如MD5加密的接口文档&#xff1a; 请求URL&#xff1a;http://101.34.221…

面试算法-105-相交链表

题目 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回…

各大pdf转word软件都用的哪家的ocr引擎?

国内一般的PDF软件一般都调用某国际PDF原厂的OCR接口&#xff0c;但这家公司是主要做PDF&#xff0c;在OCR方面并不专注&#xff0c;一些不是很复杂的场景还能应付得过来&#xff0c;复杂一点的效果就强差人意了&#xff0c;推荐用金鸣表格文字识别系统&#xff0c;它主要有以下…

抖音视频关键词无水印下载软件|手机网页视频批量提取工具

全新视频关键词无水印下载软件&#xff0c;助您快速获取所需视频&#xff01; 随着时代的发展&#xff0c;视频内容已成为人们获取信息和娱乐的重要途径。为了方便用户获取所需视频&#xff0c;推出了一款功能强大的视频关键词无水印下载软件。该软件主要功能包括关键词批量提取…

yolov8直接调用zed相机实现三维测距(python)

yolov8直接调用zed相机实现三维测距&#xff08;python&#xff09; 1. 相关配置2. 相关代码3. 实验结果 相关链接 此项目直接调用zed相机实现三维测距&#xff0c;无需标定&#xff0c;相关内容如下&#xff1a; 1.yolov5直接调用zed相机实现三维测距&#xff08;python&#…

ISAC代码仿真学习笔记

文章目录 A. MIMO Communication ModelB. MIMO Radar Model III. Joint Waveform and Phase Shift Matrix Design for Given Radar BeampatternA. Problem FormulationB. Proposed Algorithm V. S IMULATION RESULTS A. MIMO Communication Model 用户处的接收信号矩阵由 Y …

Spring Boot 实现定时任务动态管理

前言 本文主要介绍了SpringBoot架构下动态定时任务的使用&#xff0c;定时任务表达式配置在数据库中&#xff0c;通过反射执行到目标方法。 Quartz Quartz 是一个开源的作业调度框架,支持分布式定时任务&#xff0c;Quartz定时任务据我了解可分为Trigger&#xff08;触发器&…

小迪安全47WEB 攻防-通用漏洞Java 反序列化EXP 生成数据提取组件安全

#知识点&#xff1a; 1、Java 反序列化演示-原生 API 接口 2、Java 反序列化漏洞利用-Ysoserial 使用 3、Java 反序列化漏洞发现利用点-函数&数据 4、Java 反序列化考点-真实&CTF 赛题-审计分析 #内容点&#xff1a; 1、明白-Java 反序列化原理 2、判断-J…

javaWeb在线考试系统

一、简介 在线考试系统是现代教育中一项重要的辅助教学工具&#xff0c;它为学生提供了便捷的考试方式&#xff0c;同时也为教师提供了高效的考试管理方式。我设计了一个基于JavaWeb的在线考试系统&#xff0c;该系统包括三个角色&#xff1a;管理员、老师和学生。管理员拥有菜…

Knative 助力 XTransfer 加速应用云原生 Serverless 化

作者&#xff1a;元毅 公司介绍 XTransfer 是一站式外贸企业跨境金融和风控服务公司&#xff0c;致力于帮助中小微企业大幅降低全球展业的门槛和成本&#xff0c;提升全球竞争力。公司连续7年专注 B2B 外贸金融服务&#xff0c;已成为中国 B2B 外贸金融第一平台&#xff0c;目…

荟萃分析R Meta-Analyses 2----发现R

2.1安装R和R Studio 在开始之前&#xff0c;我们必须下载并准备一个计算机程序&#xff0c;该程序使我们能够方便地使用R进行统计分析。目前最好的选择可能是R Studio。该程序为我们提供了一个用户界面&#xff0c;使我们可以更轻松地处理数据、包和输出。最好的部分是 R Studi…

python编写API接口实现数据筛选、查询与分页

目录 一、背景 二、代码 一、背景 由于系统上需要分页展示数据&#xff0c;并提供按字段筛选数据的功能&#xff0c;于是需要我写个接口&#xff0c;以供前端使用。 接口可以通过python flask框架实现。Flask是一个轻量级的Web框架&#xff0c;它提供了足够的灵活性来构建定…

学会Sass的高级用法,减少样式冗余

在当今的前端开发领域&#xff0c;样式表语言的进步已经显著提升了代码组织性和可维护性。Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;作为CSS预处理器的翘楚&#xff0c;以其强大的变量、嵌套规则、混合宏&#xff08;mixin&#xff09;、循环和函数等高…

STM32学习笔记(6_5)- TIM定时器的输出捕获原理

无人问津也好&#xff0c;技不如人也罢&#xff0c;都应静下心来&#xff0c;去做该做的事。 最近在学STM32&#xff0c;所以也开贴记录一下主要内容&#xff0c;省的过目即忘。视频教程为江科大&#xff08;改名江协科技&#xff09;&#xff0c;网站jiangxiekeji.com 现在开…

ASR-LLM-TTS 大模型对话实现案例;语音识别、大模型对话、声音生成

参考:https://blog.csdn.net/weixin_42357472/article/details/136305123(llm+tts) https://blog.csdn.net/weixin_42357472/article/details/136411769 (asr+vad) 这里LLM用的是chatglm;电脑声音播报用的playsound 代码: ##运行 python main.pymain.py from multipro…

mac电脑下安装和启动nginx

一,安装homebrew 必须安装了homebrew&#xff0c;可在终端输入命令brew -v查看是否已经安装,没安装的话安装一下: 如果未安装先安装&#xff08;网上很多文章&#xff09; 二,查看nginx是否存在 使用命令:brew search nginx查看nginx是否存在: 不存在的话,就使用brew inst…

mac 系统如何生成秘钥

1.打开终端&#xff0c;输入 cd ~/.ssh 进入.ssh目录&#xff0c;输入 ls 检查是否已经存在SSH密钥。如果看到类似 id_rsa.pub 的文件&#xff0c;说明已经有一对公钥和私钥&#xff0c;不用新建&#xff0c;直接查看就可以&#xff0c;如果没有需要生成新的密钥。 2.在终端输…