多线程合并练习题,线程安全(售票任务引入)--学习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,一经查实,立即删除!

相关文章

计算机视觉的研究方向

随着科技的快速发展&#xff0c;计算机视觉已成为人工智能领域的一颗璀璨明星。从识别照片中的人物&#xff0c;到自动驾驶汽车的视觉系统&#xff0c;再到医学诊断的辅助工具&#xff0c;计算机视觉正以前所未有的方式改变着我们的生活。在这篇文章中&#xff0c;我们将探讨计…

uniapp先显示提示消息再返回上一页

一、描述 在有些业务场景中&#xff0c;需要先弹出提示后&#xff0c;再返回上一页。 二、思路 使用定时器&#xff0c;先弹出提示消息&#xff0c;然后开个定时器俩秒后再执行&#xff0c;返回上一页的操作&#xff0c;并且清除定时器。 三、实现 uni.showToast({title: …

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、成本控制压…

复试专业前沿问题问答合集2

复试专业前沿问题问答合集2 计算机视觉基础知识问答 Q1: 计算机视觉是什么? A1: 计算机视觉是人工智能的一个分支,它使计算机和系统能够从图像和视频中提取信息、分析和理解视觉内容。它结合了图像处理、模式识别和机器学习等技术,以模拟人眼的视觉感知能力。 Q2: 计算机…

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

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

GPT结合R语言回归模型、多元统计分析、混合效应模型、结构方程实战案例

查看原文>>>科研新边界&#xff1a;GPT & R语言联手&#xff0c;让数据分析不再难&#xff01; 自2022年GPT&#xff08;Generative Pre-trained Transformer&#xff09;大语言模型的发布以来&#xff0c;它以其卓越的自然语言处理能力和广泛的应用潜力&#xf…

jmeter中参数加密

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

【笔试】2023年秋招部分笔试(JD,58、MI,B站,雷火)

文章目录 1、京东笔试2、58笔试&#xff08;dp&#xff09;3、B站笔试&#xff08;sql/leetcode&#xff09;4、小米15、小米26、网易雷火 这边的笔试都是带选择题的&#xff0c;编程题部分占比只有一半上下。 我这里主要只记录下算法题部分的&#xff0c;毕竟单选多选反正408我…

面试算法-105-相交链表

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

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

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

【Java学习】JVM:探索Java虚拟机的黑科技与无限可能

1. 概述&#xff1a; Java虚拟机&#xff08;JVM&#xff09;是Java程序运行的核心&#xff0c;它负责将Java字节码转换为特定平台上的机器码并执行。JVM包含了七大核心系统&#xff0c;它们共同协作以支持Java程序的运行和管理。本文将从基础理论到高级应用&#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;目…