Java线程死锁-DeadLock

我们从一个比较形象的例子来了解什么是DeadLock:

狗剩和铁蛋两个小孩是好朋友,是烧一根玉米棒子都要从中间掰开,热乎乎的两个人对着啃那种。
不过好朋友也有闹矛盾的时候,这次在村头玩泥巴的时候就打架了,各自拉着对方的衣服不松手。
铁蛋还说谁先松手谁是狗,我们的狗剩哪能认怂,当即就答应了。
铁蛋的大爷在不远处乘凉,看见他俩打架就拄着拐棍挪了过来,
到跟前一看这形势就对自家大孙子说:“铁蛋,快把手松开”。
只见铁蛋喘着粗气,脸一迈,用后脑勺给他大爷回了一句:“他先松我再松”。
(这里我们注意铁蛋的想法:我正抓着狗剩的衣服,在狗剩松手之前,我是不会松开的。
线程T1保持对资源R2的占用,同时请求资源R1,等待线程T2释放对资源R1的占用。
铁蛋大爷又看向狗剩:“狗剩啊,你比他懂事,你先松开行不”。
狗剩吸溜了一下眼看流到嘴里的鼻涕:“他不松手我也不松”。
(狗剩的条件:只有铁蛋松手之后,我才会松开。—线程T2占用资源R1,等待线程T1释放资源R2。
这样这俩就僵持在这儿了。
铁蛋大爷训到:“铁蛋,赶紧松开”。
铁蛋还气哼哼的:“凭啥我先,不松”,“松开”,“我就不”。
气的他大爷照他头上来了一拐棍,这下铁蛋立马哭着松手了,狗剩几乎也是同时松开,僵局被打破了。

我们把狗剩和铁蛋想象成两个线程:铁蛋T1、狗剩T2。资源:铁蛋衣服R1、狗剩衣服R2。
T1占用R2(铁蛋抓着狗剩衣服不放),请求资源R1(铁蛋想重新获取对自己衣服的掌控)。
狗剩当然也不甘示弱,僵持不下。

死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

这里的外力就是铁蛋大爷照铁蛋头上那一拐棍。
在这里插入图片描述
但是实际环境中的死锁往往要比这个复杂的多,有可能会是多个线程形成一个等待环路。
在这里插入图片描述
Java死锁产生的四个必要条件:

1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用。

2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

如果不恰当地使用了锁,且要尝试锁住多个资源时,就可能会出现死锁情况。

package com.example.multithread;

/**
 * @author yangwei
 * @describition TODO
 *
 * @time 2020年8月
 */
public class DeadLock {

	public static String R1 = "铁蛋的衣服";
	public static String R2 = "狗剩的衣服"; 
	
	public static void main(String[] args) throws Exception {
		new Thread(new Thread1()).start();
		Thread.sleep(1000);
		new Thread(new Thread2()).start();
		Thread.sleep(1000);
	}
	
}

/**
 * @author yangwei
 * @describition 这是铁蛋
 *
 * @time 2020年8月
 */
class Thread1 implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			System.out.println(System.currentTimeMillis() + "-T1开始运行!");
			synchronized (DeadLock.R2) { // 抓住狗剩衣服
				System.out.println(System.currentTimeMillis() + "-铁蛋抓住了" + DeadLock.R2 + "!");
				Thread.sleep(3000); // 给狗剩时间让他抓住铁蛋衣服
				synchronized (DeadLock.R1) { // 铁蛋尝试恢复对自己衣服的掌控
					System.out.println(System.currentTimeMillis() + "-狗剩松开了" + DeadLock.R1 + "!");
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
}

/**
 * @author yangwei
 * @describition 这是狗剩
 *
 * @time 2020年8月
 */
class Thread2 implements Runnable {
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			System.out.println(System.currentTimeMillis() + "-T2开始运行!");
			synchronized (DeadLock.R1) { // 抓住铁蛋衣服
				System.out.println(System.currentTimeMillis() + "-狗剩抓住了" + DeadLock.R1 + "!");
				Thread.sleep(3000); // 给铁蛋时间让他抓住狗剩衣服
				synchronized (DeadLock.R2) { // 狗剩尝试恢复对自己衣服的掌控
					System.out.println(System.currentTimeMillis() + "-铁蛋松开了" + DeadLock.R2 + "!");
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
}

在这里插入图片描述
我们可以看到从6:05开始到6:10,他们两个已经僵持5分钟了。

让铁蛋爷爷的拐棍再飞一会儿…
因为我得去挤公交了。。。

Semaphore

Semaphore是一种基于计数的信号量。
它可以设置线程竞争资源的超时时间,一旦超时,转而去做其它处理,而不是一直阻塞。

猜你喜欢

转载自blog.csdn.net/qq_35549286/article/details/108129827