详解java中产生死锁的原因及如何避免
java中产生死锁的原因及如何避免 java中的死锁是一个常见的问题,它会导致程序的崩溃甚至是系统的崩溃。因此,了解java中产生死锁的原因和如何避免是非常重要的。 java中产生死锁的原因 在java中,死锁是指两个或多个线程之间由于锁的原因而相互等待的情况。这种情况下,每个线程都在等待另一个线程释放它所需的锁,这样会导致所有的线程都无法继续执行下去。 最简单的情况是一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2永远被阻塞了。这是最容易理解也是最简单的死锁的形式。 但是实际环境中的死锁往往比这个复杂的多。可能会有多个线程形成了一个死锁的环路,比如:线程T1持有锁L1并且申请获得锁L2,而线程T2持有锁L2并且申请获得锁L3,而线程T3持有锁L3并且申请获得锁L1,这样导致了一个锁依赖的环路:T1依赖T2的锁L2,T2依赖T3的锁L3,而T3依赖T1的锁L1。从而导致了死锁。 从这两个例子,我们可以得出结论,产生死锁可能性的最根本原因是:线程在获得一个锁L1的情况下再去申请另外一个锁L2,也就是锁L1想要包含了锁L2,也就是说在获得了锁L1,并且没有释放锁L1的情况下,又去申请获得锁L2,这个是产生死锁的最根本原因。另一个原因是默认的锁申请操作是阻塞的。 java中如何避免死锁 既然我们知道了产生死锁可能性的原因,那么就可以在编码时进行规避。Java是面向对象的编程语言,程序的最小单元是对象,对象封装了数据和操作,所以Java中的锁一般也是以对象为单位的,对象的内置锁保护对象中的数据的并发访问。 所以如果我们能够避免在对象的同步方法中调用其它对象的同步方法,那么就可以避免死锁产生的可能性。例如,以下代码就存在死锁的可能性: public class ClassB { private String address; // ... public synchronized void method1(){ // do something } // ... } public class ClassA { private int id; private String name; private ClassB b; // ... public synchronized void m1(){ // do something b.method1(); } // ... } 上面的ClassA.m1()方法,在对象的同步方法中又调用了ClassB的同步方法method1(),所以存在死锁发生的可能性。 我们可以修改如下,避免死锁: public class ClassA { private int id; private String name; private ClassB b; // ... public void m2(){ synchronized(this){ // do something } b.method1(); } // ... } 这样的话减小了锁定的范围,两个锁的申请就没有发生交叉,避免了死锁的可能性,这是最理性的情况,因为锁没有发生交叉。 但是有时是不允许我们这样做的。此时,如果只有ClassA中只有一个m1这样的方法,需要同时获得两个对象上的锁,并且不会将实例属性b溢出(return b;),而是将实例属性b封闭在对象中,那么也不会发生死锁。因为无法形成死锁的闭环。 但是如果ClassA中有多个方法需要同时获得两个对象上的锁,那么这些方法就必须以相同的顺序获得锁。比如银行转账的场景下,我们必须同时获得两个账户上的锁,才能进行操作,两个锁的申请必须发生交叉。这时我们也可以打破死锁的那个闭环,在涉及到要同时申请两个锁的方法中,总是以相同的顺序来申请锁,比如总是先申请id大的账户上的锁,然后再申请id小的账户上的锁,这样就无法形成导致死锁的那个闭环。 public class Account { private int id; // 主键 private String name; private double balance; public void transfer(Account from, Account to, double money){ if(from.getId() > to.getId()){ synchronized(from){ synchronized(to){ // transfer } } }else{ synchronized(to){ synchronized(from){ // transfer } } } } } java中的死锁是一个非常复杂的问题,它需要开发者对java中的锁机制有深入的了解,并且需要在编码时进行规避。只有这样,我们才能编写出更加健壮和高效的java程序。
- 粉丝: 4
- 资源: 910
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助