[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 + "得到了班基拉斯");
			}
	}
}

最后,我们可以总结一下
产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不释放
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

只要破解其中一个或多个条件,就可以避免死锁发生

posted @   ZoeXxx  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示