剖析Java中死锁的原因以及实现

Java基础

浏览数:181

2019-11-2

死锁的原因

首先,产生死锁需要两个锁对象(假设A,B),两个线程同时运行,并使用两个锁对象。简单的说就是锁A等待锁B释放,而锁B等待锁A释放,这样就产生了所谓的死锁。当然产生死锁的机率并不是100%,而是有一定的机率;原因是CPU在线程之间切换是没有规律的,所以产生死锁,具体看CPU的调度。请看下面实现代码,再进一步剖析:

public class DieLock {
    public static final Object LOCK_A = new Object();
    public static final Object LOCK_B = new Object();

    public static void main(String[] args) {
        // 线程一
        new Thread(() ->{
            System.out.println("Thread a starter");
            synchronized (LOCK_A) {
                System.out.println("Thread a: into lock a!");
                synchronized (LOCK_B) {
                    System.out.println("Thread a: into lock b!");
                }
                System.out.println("Thread a: release lock b!");
            }
            System.out.println("Thread a: release lock a!");
        }).start();

        // 线程二
        new Thread(() ->{
            System.out.println("Thread b starter");
            synchronized (LOCK_B) {
                System.out.println("Thread b: into lock b!");
                synchronized (LOCK_A) {
                    System.out.println("Thread b: into lock a!");
                }
                System.out.println("Thread b: release lock a!");
            }
            System.out.println("Thread b: release lock b!");
        }).start();
    }
}

分析

  • 首先定义两个锁对象,在java中所有对象都可以做锁对象,这里选择Object:LOCK_A,LOCK_B。

  • 启动了两个线程,两个线程中都有两个同步锁,第一个是锁B在锁A的里面,第二个是锁A在锁B的里面,就是两个锁交叉使用。也就是两个同步代码块,在执行进入到代码块时,锁对象已经被锁住,代码块执行完锁对象释放。

  • 大家都知道CPU在线程之间随机快速切换,我们分析这段代码看出现死锁的情况:

    1. 当第一个线程执行到第一个同步代码块时,LOCK_A对象已经被锁住;CPU快速切换到第二个线程,执行第一个代码块LOCK_B对象被锁住。
    2. CPU又切回到第一个线程,程序继续执行,第一个线程现在要执行第二个同步代码块,此时程序中LOCK_B对象已经被锁住,无法往下面执行;CPU切换到线程二,同理往下执行,而LOCK_A也被锁住了。此时:两个线程相互等待对方的锁释放,两边都释放不了,就是产生了死锁现象。
  • 以上是个人拙见,若有不对之处,感谢指正,感谢阅读.

作者:JasonDev