JavaEE初阶Day 7:多线程(5)

目录

  • Day 7:多线程(5)
    • 1. 死锁
    • 2. 死锁场景
    • 3. 场景二:两个线程,两把锁
    • 4. 场景三:N个线程,M把锁
    • 5. 避免死锁问题
    • 6. 内存可见性问题

Day 7:多线程(5)

回顾synchronized

  • synchronized带有(),填写锁对象,锁对象存在的意义,只是起到“身份标识”效果
  • 两个线程是否是针对同一个对象加锁,如果是,就可能产生阻塞/锁竞争/锁冲突
  • synchronized{},进入代码块,就相当于加锁操作,出了代码块,就相当于解锁操作
  • 修饰普通方法,相当于针对this加锁,修饰静态方法,相当于针对类对象加锁

1. 死锁

package thread;class Counter2 {private int count = 0;void add() {synchronized (this) {count++;}}int get() {return count;}
}public class Demo21 {public static void main(String[] args) throws InterruptedException {Counter2 counter2 = new Counter2();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter2.add();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {synchronized (counter2) {counter2.add();}}});t2.start();t1.start();t2.join();t1.join();System.out.println("count = " + counter2.get());}
}

上述线程t2的代码相当于

Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {synchronized (counter2) {synchronized (counter2){count++;}}}
});

假设t2先启动(t1先不考虑),t2第一次加锁,肯定能加锁成功,当t2尝试第二次加锁的时候,此时counter2变量,属于已经被锁定的状态了,针对一个已经被锁定的对象加锁,就会出现阻塞等待,阻塞到对象被解锁为止

  • 要想获得到第二层的锁,就要执行完第一层的代码块
  • 要想执行完第一层代码块,就需要先获取到第二层的锁

这种情况下,就叫“死锁”

但是在实际上述过程中,对于synchronized是不适用的,synchronized上述代码是不会出现死锁的,但是如果是C++/Pyhton的锁就会出现死锁

  • synchronized在内部进行了特殊处理(JVM)
  • 每个锁对象里,会记录当前是哪个线程持有了这个锁,当针对这个对象加锁操作时,就会先判定一下,当前尝试加锁的线程,是否是持有同一锁的线程,如果不是,就阻塞,如果是,直接放行
  • 这种机制称为**“可重入锁”**,目的是为了避免程序员粗心大意,搞出死锁

注意:当加了多层锁的时候,代码执行到哪里要真正进行解锁呢

一定是在遇到最外层的},那么,如何确定遇到的}是最外层的,运行时,给锁对象里也维护一个计数器(int n),每次遇到{,n++(只有第一次才真正加锁),当遇到}就n–,当n减到0了,才真正解锁

2. 死锁场景

死锁有三种比较典型的场景

(1)场景一:锁是不可重入锁,并且一个线程针对一个锁对象,连续加锁两次,通过引入可重入锁,可以解决上述问题

(2)场景二:两个线程,两把锁

(3)场景三:N个线程,M把锁

3. 场景二:两个线程,两把锁

有线程1和线程2,以及锁A和锁B,现在线程1和2都需要获取到锁A和锁B(拿到锁A之后,不释放A,继续获取锁B),即先让两个线程分别拿到一把锁,然后去尝试获取对方的锁

举个例子:健康码崩了,程序员回到公司修复bug,被保安拦住了

  • 保安:出示健康码,才能进公司
  • 程序员:我得进公司修复bug,才能出示健康码

类似于:家钥匙锁车里了,车钥匙锁家里了

package thread;public class Demo22 {public static void main(String[] args) throws InterruptedException {Object locker1 = new Object();Object locker2 = new Object();Thread t1 = new Thread(() ->{synchronized (locker1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker2){System.out.println("t1 获取了两把锁");}}});Thread t2 = new Thread(()->{synchronized (locker2){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (locker1){System.out.println("t2 获取了两把锁");}}});t1.start();t2.start();t1.join();t2.join();}
}

上述代码:

  • t1尝试针对locker2加锁,就会阻塞等待,等待t2释放locker2
  • t2尝试针对locker1加锁,也会阻塞等待,等待t1释放locker1

在这里插入图片描述

当遇到死锁问题,可以通过上述调用栈+状态进行定位

4. 场景三:N个线程,M把锁

随着线程数目/锁的个数增加,此时情况就更复杂了,更容易出现死锁

哲学家就餐问题

现在桌子上均匀摆放有5根筷子,总共有5位哲学家,也就是说每位哲学家左右两边各一双筷子,每一位哲学家要做的事情就是放下筷子或者拿起左右两根筷子,但是每个哲学家什么时候放下筷子,什么时候拿起左右两根筷子是不确定的(抢占式执行)

如果出现下列极端情况,就相当于死锁了

  • 同一时刻,所有的哲学家都拿起左边的筷子,那么此时所有的哲学家都无法拿起右手的筷子
  • 假如哲学家都是比较固执的人,不能拿起两双筷子,就绝对不会放下手里的筷子

上述就是非常典型的死锁情况

死锁是非常严重的问题:死锁会使线程被卡住,没办法继续工作了,而且死锁这种bug,往往都是概率性出现

5. 避免死锁问题

死锁的四个必要条件

  • 锁具有互斥特性:这个是锁的基本特性,一个线程拿到锁之后,其他线程就得阻塞等待
  • 锁不可抢占(不可被剥夺):锁的基本特点,一个线程拿到锁之后,除非自己主动释放锁,否则别人抢不走
  • 请求和保持:属于代码结构层面,一个线程拿到一把锁之后,不释放这个锁的前提下,再尝试获取其他锁
  • 循环等待:属于代码结构层面,多个线程获取多个锁的过程中,出现了循环等待,A等待B,B又等待A

必要条件缺一不可,任何一个死锁的场景,都必须同时具备上述四点

当代码中,确实需要用到多个线程获取多把锁,一定要记得约定好加锁的顺序,就可以有效避免死锁了

6. 内存可见性问题

package thread;import java.util.Scanner;public class Demo23 {private static int count = 0;public static void main(String[] args) {Thread t1 = new Thread(()->{while (count==0){}System.out.println("t1执行结束");});Thread t2 =new Thread(()->{Scanner scanner = new Scanner(System.in);System.out.println("请输入一个整数:");count = scanner.nextInt();});t1.start();t2.start();}
}

上述代码,当t2线程读到一个不为0的整数的时候,预期t1就会结束循环,但是结果并非如此

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

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

相关文章

银行账户 码题集

输入案例&#xff1a; 5 5 2 2 2 2 2 1 2 1.5 2 1 1.5 1 2 1.5 2 1 1.5 1 2 1.5输出&#xff1a;2.00 题目关键&#xff1a; 仔细读题目要求&#xff0c;转出账户被盗取z&#xff0c;转入账户转入z的整数部分&#xff0c;盗取者赚Z的小数部分的蝇头小利。且先转账&#xff0c;…

操作系统(第四周 第二堂)

目录 回顾 进程运行 进程的创建 进程的工作 举例 进程的删除 举例1&#xff08;走到return 0结束&#xff09; 举例2&#xff08;利用exit&#xff08;1&#xff09;结束&#xff09; 进程通信 共享内存 生产者算法 消费者算法 消息传递 定义 算法实现 总结 回顾…

BD202311夏日漫步(最少步数,BFS或者 Dijstra)

本题链接&#xff1a;码蹄集 题目&#xff1a; 夏日夜晚&#xff0c;小度看着庭院中长长的走廊&#xff0c;萌发出想要在上面散步的欲望&#xff0c;小度注意到月光透过树荫落在地砖上&#xff0c;并且由于树荫的遮蔽度不通&#xff0c;所以月光的亮度不同&#xff0c;为了直…

【蓝桥杯】第十五届填空题a.握手问题

题解&#xff1a; 根据问题描述&#xff0c;总共有 50 人参加会议&#xff0c;每个人除了与自己以外的其他所有人握手一次。但有 7 个人彼此之间没有进行握手&#xff0c;而与其他所有人都进行了握手。 首先&#xff0c;计算所有人进行握手的总次数&#xff1a; 总人数为 50 …

每日OJ题_01背包③_力扣494. 目标和(dp+滚动数组优化)

目录 力扣494. 目标和 问题解析 解析代码 滚动数组优化代码 力扣494. 目标和 494. 目标和 难度 中等 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; …

AI论文速读 |(图腾) TOTEM:通用时间序列分析的token化时间序列嵌入表示

题目&#xff1a;TOTEM: TOkenized Time Series EMbeddings for General Time Series Analysis 作者&#xff1a;Sabera Talukder ; Yisong Yue ; Georgia Gkioxari 机构&#xff1a;加州理工学院&#xff08;Caltech&#xff09; 网址&#xff1a;https://arxiv.org/abs/24…

【DL水记】循环神经网络RNN的前世今生,Transformer的崛起,Mamba模型

文章目录 RNN网络简介传统RNN网络结构RNN的分类 长-短期记忆网络 (LSTM)GRU网络横空出世的Transformer网络Self-AttentionVisionTransformer Mamba模型Reference: RNN网络简介 “当人类接触新事物时&#xff0c;他们不会从头开始思考。就像你在阅读这篇文章时&#xff0c;你会根…

2024常见性能测试工具!

一&#xff1a;如何选择性能工具 选择性能测试工具时&#xff0c;可以从以下几个方面进行考虑&#xff1a; 1. 需求匹配&#xff1a;首先要明确项目的具体需求&#xff0c;比如需要测试的应用类型、协议、负载规模等。确保所选工具能够满足这些需求。 2. 技术兼容性&#xf…

MySQL进阶二

目录 1.使用环境 2.排序窗口函数 3.聚合窗口函数 1.使用环境 数据库&#xff1a;MySQL 8.0.30 客户端&#xff1a;Navicat 15.0.12 接续MySQL进阶一&#xff1a; MySQL进阶一-CSDN博客文章浏览阅读452次&#xff0c;点赞9次&#xff0c;收藏4次。MySQL进阶操作一。https…

科软24炸穿了,25还能冲吗?

25考研&#xff0c;科软必然保持大热 不是吧兄弟&#xff0c;明眼人都能看出来&#xff0c;科软以后不会出现大冷的局面了&#xff0c;除非考计算机的人减少&#xff0c;因为科软简直是叠满了buff&#xff0c;首先科软的专业课是22408&#xff0c;考的是数学二&#xff0c;这就…

Kubernetes 升级不弃 Docker:KubeKey 的丝滑之道

作者&#xff1a;尹珉&#xff0c;KubeSphere Ambaasador&Contributor&#xff0c;KubeSphere 社区用户委员会杭州站站长。 引言 随着 Kubernetes 社区的不断发展&#xff0c;即将迎来 Kubernetes 1.30 版本的迭代。在早先的 1.24 版本中&#xff0c;社区作出一个重要决策…

外贸公司应该怎么选择企业邮箱?哪个企业邮箱最好?

外贸公司业务的特殊性需要他们频繁进行跨国的沟通交流&#xff0c;那么外贸公司应该如何选择适合的企业邮箱呢&#xff1f;首先&#xff0c;传输邮件的稳定安全是前提&#xff0c;另外由于沟通多是国外客户&#xff0c;邮件的翻译也成为外贸公司企业邮箱的刚需。小编今天就详细…