admin 管理员组文章数量: 1087678
Java 进阶—死锁造成原因及其解决
今天我们来了解一下线程死锁,死锁很好理解,从字面上来看就是锁死了,解不开,在大街上看到一对卧龙凤雏的情侣,怎么说,你们给我锁死,不要分开去霍霍别人
之前我们不是说过,解决线程安全的方法就是给线程上锁,java进阶—线程安全问题,但上锁也会有死锁的情况
那么,死锁是什么?先举个通俗点的例子 小明跟小红分别同时参加两个会议,这时候办公室刚好只有一台笔记本(在小红手上),一台投影仪(在小明手上),这是两个都想要对方的东西,两人互不相让,开始争执,这样都开不成会议,就形成了死锁
把小明跟小红换成两个线程,所以,一句话,死锁就是两个或两个以上的线程争夺彼此的锁,造成阻塞
从这里我们也可以看到死锁产生的条件
-
首先,死锁产生需要两个或者两个以上线程 (例子中的小明跟小红)
-
两个或者两个以上的锁 (例子中的 笔记本跟投影仪)
-
两个或两个以上线程持有不同锁(例子中小明有投影仪,小红有笔记本)
-
持有不同锁线程争夺对方的锁 (例子中小明跟小红抢对方的东西)
用代码来解释上述例子
我们按照死锁的四个条件一步一步来
1. 首先有两个线程
一个小明类,一个小红类
2. 两个锁
小明类 里面 有 投影仪锁 , 小红类里面有电脑锁
3. 两个线程持有不同的锁
小明重写run 方法 调用 投影仪 锁
小红重写run 方法 调用 笔记本 锁
4. 持有不同锁调用对方的锁
小明在projector 里面去调用 小红的computer
小红在computer里面去调用 小红的projector
public class XiaoMing implements Runnable{@Overridepublic void run() {//小明持有投影仪这个锁projector();}/*** 投影仪这个锁 static 一个资源*/public static synchronized void projector() {try {//线程休眠2秒,目的为了执行慢一点,更方便看出效果Thread.sleep(2000);} catch (InterruptedException e) { e.printStackTrace();}System.out.println("小明的投影仪"); // 获取小红的锁XiaoHongputer();}
}
public class XiaoHong implements Runnable{@Overridepublic void run() { //小红持有笔记本这个锁computer();}/*** 笔记本这个锁 static 一个资源*/public static synchronized void computer() {try {//线程休眠2秒Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("小红的笔记本");//获取小明的锁XiaoMing.projector();}
}
我们去启动这两个线程
public static void main(String[] args) {//创建小红线程XiaoHong xiaoHong =new XiaoHong();Thread thread =new Thread(xiaoHong);//创建小明线程XiaoMing xiaoMing = new XiaoMing();Thread thread1 =new Thread(xiaoMing);//启动thread.start();thread1.start();}
执行结果:
程序在打印两个结果后,两个程序在相互争夺资源,程序停止需要借助外力
解决死锁也就很简单了,我们不去拿对方的锁就好了
这一步,我们不去调用对方的锁,
看看效果:
可以看到程序正常终止了
要是不太明白,我们再来看一个更直观的代码:(注意看代码中的注释)
还是有这么两个资源,电脑跟投影仪
public class Person implements Runnable {/*** 只有一份资源,电脑 跟 投影仪*/static final Computer COMPUTER = new Computer();static final Projector PROJECTOR = new Projector();/*** 类型 0 代表 小红 1代表小明*/int type;/*** 人名*/String name;public Person(int type, String name) {this.type = type;this.name = name;}@Overridepublic void run() {//开始抢占资源try {getSource();} catch (InterruptedException e) {e.printStackTrace();}}private void getSource() throws InterruptedException {//让小明先拿投影仪if (type==1) {synchronized (PROJECTOR) {System.out.println(this.name+"获得投影仪");Thread.sleep(2000);//小明拿到投影仪,又想去拿电脑synchronized (COMPUTER) {System.out.println(this.name+"获得电脑");}}}else {//小红拿到电脑,又想去拿投影仪synchronized (COMPUTER) {System.out.println(this.name+"获得电脑");Thread.sleep(1000);synchronized (PROJECTOR) {System.out.println(this.name+"获得投影仪");}}}}}
启动两个线程
public static void main(String[] args) {Person person =new Person(1,"小明");Person person2 =new Person(0,"小红");Thread thread =new Thread(person);Thread thread1 =new Thread(person2);thread.start();thread1.start();}
执行结果:
程序进入了死锁
怎么解决?一样的,获取到锁的同时不去调用对方的锁,我们这两段代码放到外边来
变成下面这样
package com.xrp.flinkDemo.demo;public class Person implements Runnable {/*** 只有一份资源,电脑 跟 投影仪*/static final Computer COMPUTER = new Computer();static final Projector PROJECTOR = new Projector();/*** 类型 0 代表 小红 1代表小明*/int type;/*** 人名*/String name;public Person(int type, String name) {this.type = type;this.name = name;}@Overridepublic void run() {//开始抢占资源try {getSource();} catch (InterruptedException e) {e.printStackTrace();}}private void getSource() throws InterruptedException {//让小明先拿投影仪if (type==1) {synchronized (PROJECTOR) {System.out.println(this.name+"获得投影仪");Thread.sleep(2000);}synchronized (COMPUTER) {System.out.println(this.name+"获得电脑");}}else {//小红拿到电脑,又想去拿投影仪synchronized (COMPUTER) {System.out.println(this.name+"获得电脑");Thread.sleep(1000);}synchronized (PROJECTOR) {System.out.println(this.name+"获得投影仪");}}}}
再执行看看:
可以发现解决了死锁问题,并且都获得了想要的资源
好了,以上便是死锁原因以及避免死锁方法了,主要就是不要在持有一个锁里面再去获取别的锁
【完】
本文标签: Java 进阶死锁造成原因及其解决
版权声明:本文标题:Java 进阶—死锁造成原因及其解决 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1700276953a376242.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论