多线程面试(二):在Java多线程中如何避免死锁

问:什么是线程死锁?

答案很简单,当有两个或更多的线程在等待对方释放锁并无限期地卡住时,这种情况就称为死锁。

 

问:死锁产生的必要条件?

(1) 互斥:一次只有一个进程可以使用一个资源。其他进程不能访问已分配给其他进程的资源。

(2)占有且等待:当一个进程在等待分配得到其他资源时,其继续占有已分配得到的资源。

(3)非抢占:不能强行抢占进程中已占有的资源。

(4)循环等待:存在一个封闭的进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。

 

问:设计一个死锁程序?

        代码如下,方法method1中,首先是获取String对象,然后是Integer对象;方法method2中,首先是获取Integer对象,然后是String对象。由于两个方法获取锁的顺序是相反的,可能method1方法在获取了String对象锁时,然后去获取Integer锁,发现Integer锁被method2获取了,这时候就造成了死锁。     

public class DeadLockDemo {
	/* 
	 * This method request two locks, first String and then Integer 
	 **/
	public void method1() {
		synchronized (String.class) {
			System.out.println("Aquired lock on String.class object");
			synchronized (Integer.class) {
				System.out.println("Aquired lock on Integer.class object");
			}
		}
	}
 

	public void method2() {
		synchronized (Integer.class) {
			System.out.println("Aquired lock on Integer.class object");
			synchronized (String.class) {
				System.out.println("Aquired lock on String.class object");
			}
		}
	}
}

问:如何解决死锁?

答:避免死锁的三种方式:

      1、设置加锁顺序

      2、设置加锁时限

      3、死锁检测

 

1、设置加锁顺序

     线程按照相同的顺序获取锁对象。

public class DeadLockDemo {
	/* 
	 * This method request two locks, first String and then Integer 
	 **/
	public void method1() {
		synchronized (String.class) {
			System.out.println("Aquired lock on String.class object");
			synchronized (Integer.class) {
				System.out.println("Aquired lock on Integer.class object");
			}
		}
	}
 

	public void method2() {
		synchronized (String.class) {
			System.out.println("Aquired lock on Integer.class object");
			synchronized (Integer.class) {
				System.out.println("Aquired lock on String.class object");
			}
		}
	}
}

缺点: 
     按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,并知道他们之间获取锁的顺序是什么样的。

 

2、设置加锁时限:(超时重试)

  若一个线程在一定的时间里没有成功的获取到锁,则会进行回退并释放之前获取到的锁,然后等待一段时间后进行重试。

缺点: 
      但是由于存在锁的超时,通过设置时限并不能确定出现了死锁,每种方法总是有缺陷的。有时为了执行某个任务。某个线程花了很长的时间去执行任务,如果在其他线程看来,可能这个时间已经超过了等待的时限,可能出现了死锁。

 

3、死锁检测:

       当一个线程获取锁的时候,会在相应的数据结构中记录下来,相同下,如果有线程请求锁,也会在相应的结构中记录下来。当一个线程请求失败时,需要遍历一下这个数据结构检查是否有死锁产生。

    原文作者:java锁
    原文地址: https://blog.csdn.net/qq_35571554/article/details/82861967
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞