死锁

1、概念

  死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

 2、死锁产生必备的四个条件

互斥条件:指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。

● 请求并持有条件:指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源。

● 不可剥夺条件:指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源。

● 环路等待条件:指在发生死锁时,必然存在一个线程—资源的环形链,即线程集合{T0, T1, T2, …, Tn}中的T0正在等待一个T1占用的资源,T1正在等待T2占用的资源,……Tn正在等待已被T0占用的资源。

package thread;

/**
 * @description: 死锁测试
 * @author: Raymond
 * @createDate: 2020/5/8
 * @version:
 */
public class DeadLockTest2 {

    private static Object resourceA = new Object();
    private static Object resourceB = new Object();

    public static void main(String[] args) {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    System.out.println(Thread.currentThread() + "get resourceA");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceB");
                    synchronized (resourceB) {
                        System.out.println(Thread.currentThread() + "get resourceB");
                    }
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceB) {
                    System.out.println(Thread.currentThread() + "get resourceB");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceA");
                    synchronized (resourceA) {
                        System.out.println(Thread.currentThread() + "get resourceA");
                    }
                }
            }
        });

        threadA.start();
        threadB.start();
    }
}
/**
 *  构成死锁4个必要条件分析:
 * 1、首先,resourceA和resourceB都是互斥资源,当线程A调用synchronized(resourceA)方法获取到resourceA上的监视器锁并释放前,
 * 线程B再调用synchronized(resourceA)方法尝试获取该资源会被阻塞,只有线程A主动释放该锁,线程B才能获得,这满足了资源互斥条件。
 *
 * 2、线程A首先通过synchronized(resourceA)方法获取到resourceA上的监视器锁资源,然后通过synchronized(resourceB)方法等待获取resourceB上的监视器锁资源,
 * 这就构成了请求并持有条件。
 *
 * 3、线程A在获取resourceA上的监视器锁资源后,该资源不会被线程B掠夺走,只有线程A自己主动释放resourceA资源时,它才会放弃对该资源的持有权,
 * 这构成了资源的不可剥夺条件。
 *
 * 4、线程A持有objectA资源并等待获取objectB资源,而线程B持有objectB资源并等待objectA资源,这构成了环路等待条件。所以线程A和线程B就进入了死锁状态。
 */

3、如何避免线程死锁

要想避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,但是学过操作系统的读者应该都知道,目前只有请求并持有和环路等待条件是可以被破坏的。造成死锁的原因其实和申请资源的顺序有很大关系,使用资源申请的有序性原则就可以避免死锁,那么什么是资源申请的有序性呢?对上面线程B的代码进行如下修改。

Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    System.out.println(Thread.currentThread() + "get resourceB");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceA");
                    synchronized (resourceB) {
                        System.out.println(Thread.currentThread() + "get resourceA");
                    }
                }
            }
        });

如上代码让在线程B中获取资源的顺序和在线程A中获取资源的顺序保持一致,其实资源分配有序性就是指,假如线程A和线程B都需要资源1,2,3, ...,n时,对资源进行排序,线程A和线程B只有在获取了资源n-1时才能去获取资源n。

简单分析一下为何资源的有序分配会避免死锁,比如上面的代码,假如线程A和线程B同时执行到了synchronized(resourceA),只有一个线程可以获取到resourceA上的监视器锁,假如线程A获取到了,那么线程B就会被阻塞而不会再去获取资源B,线程A获取到resourceA的监视器锁后会去申请resourceB的监视器锁资源,这时候线程A是可以获取到的,线程A获取到resourceB资源并使用后会放弃对资源resourceB的持有,然后再释放对resourceA的持有,释放resourceA后线程B才会被从阻塞状态变为激活状态。所以资源的有序性破坏了资源的请求并持有条件和环路等待条件,因此避免了死锁。

posted @ 2019-08-18 14:55  CodeCorner  阅读(113)  评论(0)    收藏  举报