线程安全(买票案例):加锁方式(synchronized、Lock锁)【同步代码块、同步方法】--学习JavaEE的day31上

day31上

线程安全 – 加锁

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

加锁方式

synchronized

Lock

synchronized

继day30的售票需求案例学习

学习思路:

1.使用线程类、任务类方式不同

2.加锁方式不同

3.对于加锁中同步代码块、同步方法不同

同步代码块:

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

…想要互斥的代码…

}//自动解锁

见day30

同步方法

同步方法 – 成员同步方法:

注意:锁对象 -> this(原因:成员方法属于对象)

public synchronized void method(){//自动上锁

…想要互斥的代码…

}//自动解锁

同步方法 – 静态同步方法:

注意:锁对象 -> 类.class(原因:静态方法属于类)

public static synchronized void method(){//自动上锁

…想要互斥的代码…

}//自动解锁

Lock

补充: Doug Lea(道格·利)编写的util.concurrent包 ;个人开发线程安全

//锁对象

Lock lock = new ReentrantLock();

lock.lock();//手动上锁

…想要互斥的代码…

lock.unlock();//手动解锁

需求

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

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

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

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

iv. 。。。

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

涉及到线程安全,要加锁

使用线程类解决需求

synchronized方式
使用同步代码块

继day30

使用同步方法
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){method();}}//锁对象:MyThread.classpublic static synchronized void method(){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();}
}

方法外面加锁,还是锁不住

原因:锁对象 -> this(原因:成员方法属于对象),new了三个对象,就有三把锁(对象)锁不住

解决:再把同步方法设置成静态变成一个锁(对象),就能锁锁上

Lock方式
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Lock lock = new ReentrantLock();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){lock.lock();//手动上锁try {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}if(curTicket >= allTicket){System.out.println("窗口" +  Thread.currentThread().getName() + "票已经售完");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();//手动解锁}}}
}

run()中new了锁对象,添加了手动上锁和手动解锁,还是锁不住

原因:线程new了三个对象,都调用run方法就有三把锁(对象)锁不住

解决:把new的锁放在run方法外面,再把new的锁对象设置成静态变成一个锁(对象),就能锁锁上

注意

考虑到想要互斥的代码有可能出现异常,如果出现异常就解不了锁,锁就用不了,用trycatch处理(鼠标右键Surround With)保证能解锁,下一次线程使用

使用任务类解决需求

synchronized方式
使用同步代码块
public class Task implements Runnable{private int allTicket = 1000;private int curTicket = 0;@Overridepublic void run() {while(curTicket < allTicket){synchronized (this) {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}}System.out.println("窗口" + Thread.currentThread().getName() + "票已售完");}}public class Test01 {public static void main(String[] args) {Task task = new Task();Thread t1 = new Thread(task, "001");Thread t2 = new Thread(task, "002");Thread t3 = new Thread(task, "003");t1.start();t2.start();t3.start();}
}
代码实现出现的问题

与day30中的不太一样,day30要求是不会出现脏数据,而现在是要保证锁对象用得好

问题一:

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

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

解决思路:curTicket和allTicket设置为成员属性,三个线程共用同一个任务

注意:

设置成静态属性和成员属性的区别:设置成成员属性,对于”铁道部发布了一个售票任务“设置成静态没有问题,但考虑到多个售票任务,静态对象就不好,售票任务之间是不同的

问题二:

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

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

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

注意:

对于锁对象,问题1提到静态的是不好的,所以使用非静态的

通常用this,原因是this表当前任务的对象,对于外部有多个任务时,就会针对不同任务相应互斥内容进行互斥

问题三:

多卖了票

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

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

注意:

1.对于两个判断为什么不写出if-else的原因:如果写出if-else,if正常执行不会再执行else,就会有一个售完票的窗口输出不了“窗口xxx票已售完”

2.对于也不写成双if判断,把售完的判断不加锁的原因:以前的代码是存在问题的,有可能正好最后一个票卖完解锁,下一次curTicket不小于allTicket就进不去了,也没办法执行判断卖完的输出

使用同步方法

使用成员属性的原因同上

public class Task implements Runnable{private int allTicket = 1000;private int curTicket = 0;@Overridepublic void run() {while(curTicket < allTicket){method();}System.out.println("窗口" + Thread.currentThread().getName() + "票已售完");}public synchronized void method(){if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在销售第" + curTicket + "张票");}}}
Lock方式

加锁参考使用线程类解决需求的lock方式,lock注意trycatch

小结:

线程类方式和任务类方式的区别:线程类方式不灵活,任务类是新建的任务交给线程更灵活,后续普遍使用任务类方式

设置成静态属性和成员属性的区别:设置成成员属性,对于”铁道部发布了一个售票任务“设置成静态没有问题,但考虑到多个售票任务,静态对象就不好,售票任务之间是不同的

总结:

1.线程安全 — 买票案例
synchronized代码块
synchronized方法(成员同步方法、静态同步方法)
Lock锁
注意:
1.加锁的方式
2.锁对象(多个线程去操作同一把锁才能互斥住)

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

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

相关文章

【Spring】Spring框架中的一个核心接口ApplicationContext 简介,以及入口 Run() 的源码分析

一、简介 ApplicationContext 是Spring框架中的一个核心接口&#xff0c;它是Spring IoC容器的实现之一&#xff0c;用于管理和组织应用程序中的各种Bean&#xff0c;同时提供了一系列功能来支持依赖注入、AOP等特性。 简单来说&#xff0c;ApplicationContext 是一个大型的、…

求两个单链表的差集

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 但行前路&#xff0c;不负韶华&#…

发车,易安联签约某新能源汽车领军品牌,为科技创新保驾护航

近日&#xff0c;易安联成功签约某新能源汽车领军品牌&#xff0c;为其 数十万终端用户 建立一个全新的 安全、便捷、高效一体化的零信任终端安全办公平台。 随着新能源汽车行业的高速发展&#xff0c;战略布局的不断扩大&#xff0c;技术创新不断引领其市场价值走向高点&am…

移动端Web笔记day03

移动 Web 第三题 01-移动 Web 基础 谷歌模拟器 模拟移动设备&#xff0c;方便查看页面效果&#xff0c;移动端的效果是当手机屏幕发生了变化&#xff0c;页面和页面中的元素也要跟着等比例变化。 屏幕分辨率 分类&#xff1a; 硬件分辨路 -> 物理分辨率&#xff1a;硬件…

GTC 2024 火线评论:DPU 重构文件存储访问

编者按&#xff1a;英伟达2024 GTC 大会上周在美国加州召开&#xff0c;星辰天合 CTO 王豪迈在大会现场参与了 GPU 与存储相关的最新技术讨论&#xff0c;继上一篇《GTC 2024 火线评论&#xff1a;GPU 的高效存储利用》之后&#xff0c;这是他发回的第二篇评论文章。 上一篇文章…

Spring框架与Spring Boot的区别和联系

引言 Spring框架和Spring Boot都是Java生态中最受欢迎的开源框架&#xff0c;它们各自扮演着不同的角色&#xff0c;帮助开发者构建高效的企业级应用。本教程将从零基础的角度出发&#xff0c;让你轻松理解这两者的区别和联系。 Spring框架简介 Spring框架&#xff0c;简称Spri…

C#中让字典、列表、数组作为只读的方法参考

一、字典 在 C# 中&#xff0c;可以通过使用 ReadOnlyDictionary<TKey, TValue> 类或者是通过调用普通字典的 .AsReadOnly() 方法来创建一个只读的字典。ReadOnlyDictionary 不允许修改字典&#xff0c;任何试图改变字典的操作都会抛出 NotSupportedException。 以下是使…

pear-admin 项目结构讲解

上一篇文章介绍了pear-admin用到flask的技术&#xff0c; 深入代码后发现其结构也是令人眼前一亮&#xff0c; 结构化&#xff0c;模块化&#xff0c; 解耦做得非常优秀。 整个项目数据库使用migrate做了版本管理&#xff0c; 使用marshmallow做了序列化&#xff0c;这样数据库…

vue实现文字一个字一个字的显示(开箱即用)

图示&#xff1a; 核心代码 Vue.prototype.$showHtml function (str, haveCallback null) {let timeFlag let abcStr for (let i 0; i < str.length; i) {(function (i) {timeFlag setTimeout(function () {abcStr str[i]haveCallback(abcStr)if ((i 1) str.length…

EPSON推出的实时时钟模块RX8130CE功耗低至300nA、从容应对各种使用场景

随着科技的进步和消费者需求的不断变化&#xff0c;笔记本电脑市场继续展现出强劲的发展势头一方面移动性和轻薄性成为主流&#xff0c;另外一方面性能在不断提升&#xff0c;功能也日益丰富。实时时钟模组&#xff0c;作为提供时间和定时功能的单元模块&#xff0c;是笔记本电…

解决错误LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to

react native pod第三方包或者git clone的时候遇到 OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443两种解决方案 方法一 修改计算机网络配置 由于使用 IPv6 的原因&#xff0c;可能会导致这一问题的出现 系统在解析hostname时使用了ipv6 可以配…

【工具】秘塔AI搜索|强烈推荐,中文免费搜索神器!堪比做报表的员工

网址&#xff1a;https://metaso.cn/ 使用时间&#xff1a;2024/03/27 以前其实用过它家的秘塔写作猫&#xff0c;当时感觉非常不错。 这次看到它出AI搜索&#xff0c;感觉开发者挺有野心和实力的。 推荐原因&#xff1a; 国产产品&#xff0c;中文适用性强。目前还免费。【不…

工业镜头常用参数之实效F(Fno.)和像圈

Fno. 工业镜头中常用到的参数F&#xff0c;有时候用F/#&#xff0c;Fno.来表示&#xff0c;指的是镜头通光能力的参数。它可用镜头焦距及入瞳直径来表示&#xff0c;也可通过镜头数值孔径&#xff08;NA&#xff09;和光学放大倍率&#xff08;β&#xff09;来计算。有效Fno.…

LeetCode题练习与总结:全排列Ⅱ

一、题目描述 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[…

IDEA使用常用的设置

一、IDEA常用设置 可参考&#xff1a;IDEA这样配置太香了_哔哩哔哩_bilibili 波波老师 二、插件 可参考&#xff1a;IDEA好用插件&#xff0c;强烈推荐_哔哩哔哩_bilibili 波波老师 三、其他 学会用点“.” IDEA弹窗Servers certificate is not trusted怎么禁止&#xf…

QEMU安装和使用@Ubuntu(待续)

参考这篇文档&#xff1a;在 QEMU 上运行 RISC-V 64 位版本的 Linux - 知乎 参考官方文档&#xff1a;Running 64- and 32-bit RISC-V Linux on QEMU — RISC-V - Getting Started Guide FreeBSD riscv下载&#xff1a;Index of /freebsd/releases/riscv/14.0-RELEASE/ Linux…

共享旅游卡到底是怎么回事?

共享旅游卡&#xff0c;一种引领旅游新风尚的智能卡片&#xff0c;正以其独特的方式改变着人们的旅游体验。千益畅行旅游卡&#xff0c;作为共享旅游卡的杰出代表&#xff0c;正逐渐成为旅游市场的新宠。 那么&#xff0c;共享旅游卡到底是什么&#xff1f;它又如何改变了我们…

计算机视觉之三维重建(4)---三维重建基础与极几何

文章目录 一、三维重建基础1.1 问题引入1.2 线性解法1.3 非线性解法1.4 多视图几何的关键问题 二、极几何与基础矩阵2.1 极几何2.2 极几何特例2.3 本质矩阵2.4 本质矩阵的性质2.5 基础矩阵2.6 基础矩阵的性质 三、基础矩阵估计 一、三维重建基础 1.1 问题引入 1. 从单张图像恢…

ROS机器人入门第四课:话题通信

文章目录 ROS机器人入门第四课&#xff1a;话题通信一、话题通信概述&#xff08;一&#xff09;概念&#xff08;二&#xff09;作用 二、话题通信基本操作需求:分析:流程:&#xff08;一&#xff09;发布方解释一些关键的ROS函数和概念&#xff1a; &#xff08;二&#xff0…

久菜盒子|医学大数据|R|常用安装包及介绍

复习下&#xff1a; library(tibble) library(readxl) library(survival) library(survminer) library(rms) library(forestplot) library(magrittr) library(corrplot) library(car) require(stringdist) library(timeROC) library(tidyverse) library(dplyr) library(tidyr)…