[Java]Java初学之多线程04--死锁
Intro
继上篇《03--同步与锁》,这篇文章着重讲讲“锁”,更具体来说,讲讲“死锁”
最近天气变冷了。。。真的冷❄
记得多穿衣服
正文
死锁
死锁是指两个或多个线程都在等待对方释放资源,最后都停止执行的情形。
举个例子来说明会更清晰:我们两个都是宝可梦世界的训练家,我有暴飞龙,你有班基拉斯,我们两个想交换宝可梦。出于完全的不信任,你看到我还没交出精灵球,你自然也不会主动把精灵球交到我手上。这样我们就面面相觑都在等对方先交出精灵球了
在现实中这种事情当然可以靠信任或者第三方(游戏内的交换系统)介入来解决。但在程序里就做不到,最终就会僵持导致程序停止执行
用代码来看看吧
package com.multiThread;
//死锁:多个线程互相抱着对方需要的资源,形成僵持
public class DeadLock {
public static void main(String args[]) {
ExchangePokemon Me = new ExchangePokemon("salamence", "Me");
ExchangePokemon You = new ExchangePokemon("tyranitar", "You");
Me.start();
You.start();
}
}
//暴飞龙
class Salamence {}
//班基拉斯
class Tyranitar {}
class ExchangePokemon extends Thread {
//用static前缀保证只有一个资源
static Salamence salamence = new Salamence();
static Tyranitar tyranitar = new Tyranitar();
String pokemon;
String name;
ExchangePokemon(String pokemon, String name) {
this.pokemon = pokemon;
this.name = name;
}
@Override
public void run() {
try {
ExchangePokemon();
} catch (InterruptedException e) {
Throw new RuntimeException(e)
}
}
private void exchangePokemon() Throws InterruptedException {
if (pokemon = "tyranitar") {
synchronized (tyranitar) {
System.out.println(this.name + "有班基拉斯");
Thread.sleep(1000);
synchronized (salamence) {
System.out.println(this.name + "得到了暴飞龙");
}
}
}else {
synchronized (salamence) {
System.out.println(this.name + "有暴飞龙");
Thread.sleep(1000);
synchronized (tyranitar) {
System.out.println(this.name + "得到了班基拉斯");
}
}
}
}
}
输出结果会卡在“我有暴飞龙” “你有班基拉斯”上,因为第二个synchronized块嵌套在第一个里面了,因此第一个没释放,就要开始执行第二个同步块了,而这两个资源我们是互相调用的,因此对方没有释放第一个锁,自然无法调用,最后导致卡死在第一步。
解决办法也非常简单,不要嵌套使用同步块即可
下面是exchangePokemon()的正确写法:
private void exchangePokemon() Throws InterruptedException {
if (pokemon = "tyranitar") {
synchronized (tyranitar) {
System.out.println(this.name + "有班基拉斯");
Thread.sleep(1000);
}
synchronized (salamence) {
System.out.println(this.name + "得到了暴飞龙");
}
}else {
synchronized (salamence) {
System.out.println(this.name + "有暴飞龙");
Thread.sleep(1000);
}
synchronized (tyranitar) {
System.out.println(this.name + "得到了班基拉斯");
}
}
}
最后,我们可以总结一下
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不释放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
只要破解其中一个或多个条件,就可以避免死锁发生
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构