Java面试问题,如何避免Java线程中的死锁?

如何避免Java中的死锁?是流行的Java面试问题之一,也是多线程的流行话题之一。尽管问题看起来很简单,但是一旦深入,大多数Java开发人员就会陷入困境。

面试问题以“什么是死锁?”当两个或多个线程正在等待彼此释放所需资源(锁定)并陷入无限时间的阻塞时,这种情况称为死锁,它只会在多任务或多线程的情况下发生。

如何检测Java中的死锁?

虽然这可能有很多答案,但我的版本是,如果我看到嵌套的同步块,或者从其他同步方法调用一个同步方法,或者试图在不同的对象上获得锁,那么如果开发人员不是非常小心,就很可能出现死锁。

另一种方法是在运行应用程序时发现线程被锁定,尝试使用线程转储,在Linux中可以通过命令“kill -3”来实现,这将打印应用程序日志文件中所有线程的状态,就可以看到哪个线程被锁定在哪个对象上。

也可以使用fastthread等工具分析线程转储,上传你的线程转储并分析它。

另一种方法是使用jConsole/VisualVM,它将准确地显示哪些线程被锁定,以及在哪个对象上。

编写一个会导致死锁的Java程序

一旦回答了前面的问题,他们可能会要求你编写导致Java死锁的代码

这是我的一个版本

/** * Java程序通过强制循环等待来创建死锁 * * @author WINDOWS 8 * */ public class DeadLockDemo { 

 /* * T此方法请求两个锁,首先是String,然后是Integer */  public void method1() {  synchronized (String.class) {  System.out.println("Aquired lock onString.classobject"); 

 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.classobject"); 

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

如果method1()和method2()都将被两个或多个线程调用,那么死锁的可能性很大,如果线程1在执行method1()时获取Sting对象上的锁,而线程2在执行method2()时获取Integer对象上的锁,那么线程2将等待对方释放Integer和String上的锁以继续执行,而这永远不会发生

此图准确演示了我们的程序,其中一个线程持有一个对象的锁并等待其他线程持有的其他对象锁。

这个图展示了我们的这个程序,一个线程持有一个对象的锁,等待另一个线程持有的其他对象锁。

你可以看到线程1想要对线程2持有的对象2的锁定,而线程2想要对线程1持有的对象1进行锁定。由于没有线程愿意放弃,所以存在死锁并且Java程序卡住了。

如何避免Java中的死锁

现在面试官来到最后一部分,这是我认为最重要的部分之一; 你如何修复代码中的死锁?或者如何避免Java中的死锁?

如果仔细查看了上面的代码,那么你可能已经发现死锁的真正原因不是多线程,而是它们请求锁定的方式,如果提供有序访问,则问题将得到解决。

这是我的固定版本,它避免了由于没有抢占的无效循环等待导致的死锁,这是需要死锁的四个条件之一。

public class DeadLockFixed { /** * 两种方法现在都以相同的顺序请求锁定,首先是Integer,然后是String。* 也可以完成反向,例如第一个String然后是Integer* 两者都会解决问题,只要两种方法都请求锁定* 按照一致的顺序*/ 	public void method1() { 		synchronized (Integer.class) {				System.out.println("Aquired lock on Integer.class object"); 

				synchronized (String.class) { 						System.out.println("Aquired lock on String.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"); 						}				 }	 			} }

现在不存在任何死锁,因为两个方法都以相同的顺序访问Integer和String类文字的锁。因此,如果线程A获取对Integer对象的锁定,则线程B将不会继续,直到线程A释放整数锁定,同样,即使线程B保持字符串锁定,线程A也不会被阻止,因为现在线程B不会期望线程A释放整数锁定继续进行。

想获取更多面试问题及答案请加QQ群:142019080

原文地址:https://www.cnblogs.com/hoober/p/10489808.html

时间: 2024-07-31 09:45:04

Java面试问题,如何避免Java线程中的死锁?的相关文章

阿里Java面试官分享初级Java程序员通过面试的技巧

本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕业生和初级程序员(一般是工作经验3年以下)大多处于事业的青黄不接的阶段,在找工作时往往会遇到缺乏实际项目经验的瓶颈,作为技术面试官,我也经常在面试过程中感受到这些候选人缺乏实际经验的缺陷.不过本人之前做过java兼职培训老师,也总结了些这批人群提升实际技能和面试技能的技巧,最近也老有人来问我这个,所

Java面试18|关于进程、线程与协程

1.IPC(Inter-Process Communication,进程间通信)与线程通信的几种方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系.# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信.# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问.它常作为一种锁机制,防止某进程正在访问共享资源

Java面试18|关于进程与线程

1.IPC(Inter-Process Communication,进程间通信)与线程通信的几种方式 异步:如队列 同步:RPC调用,如web service Java线程间通信:FutureTask.Exchanger和共享全局变量的方式

java面试基础题------》Java 中的父子类静态代码块,代码块,构造方法执行顺序

4.指出下面程序的运行结果. class A { static { System.out.print("1"); } public A() { System.out.print("2"); } } class B extends A{ static { System.out.print("a"); } public B() { System.out.print("b"); } } public class Hello { pu

java面试基础题------》Java 中List、Set、Map异同点

借鉴地址:http://blog.csdn.net/speedme/article/details/22398395 几句喜欢的话,拷贝下来: 世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合 有人想有可以自动扩展的数组,所以有了List 有的人想有没有重复的数组,所以有了set 有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree** 相同点: 1.List,Set,Map将持有对象一律视为Object型别. 2.Collection.List.Set.

送上一篇应付Java 面试的秘籍(Java 初级)

package self.learn.basicdata; import java.io.PrintStream; import java.util.Properties; public class BasicData { public static void main(String[] args) {//问题1: 类似整形变量的取值范围是什么?//Integer rage//- 2E31~ 2E31-1// ........ , ........ , ........ , ........//

Java面试(1)-- Java逻辑运算符

1 class Demo04{ 2 public static void main(String[] args){ 3 //逻辑运算符 4 5 //例1 6 System.out.println(true | false & false); 7 //结果 true 8 //Java语言中,&的优先级比|的优先级高 9 10 11 //例2 12 //三目运算符:关系表达式?值1:值2; 13 int a = 10; 14 int b = 5; 15 int c = (a>b)?(a=

Java面试(2)-- Java算数表达式

1 class Demo02{ 2 public static void main(String[] args){ 3 //算数运算符 +,-,*,/,%,++,-- 4 5 //例1 6 int a = 1; 7 int b = 2; 8 int c = 3; 9 System.out.println(a+b+c); 10 //结果 6 11 /* 12 a+b+c的执行流程 13 1:去内存中找a对应的数据 14 2:读取下一个运算符 15 3:读取a后面的操作数b,同事尧都区b后面的运算符

Java面试(3)-- Java关系运算符

1 class Demo03{ 2 public static void main(String[] args){ 3 //关系运算符 == 4 5 //例1 6 int a = 10; 7 int b = 10; 8 double c = 10.0; 9 System.out.println(a==b); 10 System.out.println(a==c); 11 //结果 true,true 12 /* 13 ==左边,右边的类型一致,直接比较 14 ==左边,右边的类型不一致,会先将a