遇见YY

导航

 

定义:死锁是指两个或者两个以上的线程在执行过程中,因争夺资源而造成的相互等待的现象。

死锁产生的四个条件:

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

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

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

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

死锁例子:

public class DeadLock {
    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 exception){
                        exception.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 exception){
                        exception.printStackTrace();;
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceA!");
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                    }
                }
            }
        });

        threadA.start();
        threadB.start();

    }
}

输出:

 

分析:本例是如何满足死锁的四个条件的。

首先,resourceA和resourceB都是互斥资源,当线程A调用synchronized(resourceA)方法获取到resourceA上的监视器锁并释放前,线程B再调用synchronized(resourceA)方法尝试获取该资源会被阻塞,只有线程A主动释放该锁,线程B才能获得,这满足了资源互斥条件

线程A首先通过synchronized(resourceA)方法获取到resourceA上的监视器锁资源,然后通过synchronized(resourceB)方法等待获取resourceB上的监视器锁资源,这就构成了持有并请求条件

线程A在获取resourceA上的监视器锁资源后,该资源不会被线程B掠夺走,只有线程A自己主动释放resourceA资源时,它才会放弃对该资源的持有权,这构成了资源的不可剥夺条件

线程A持有objectA资源并等待获取objectB资源,而线程B持有objectB资源并等待objectA资源,这构成了环路等待条件。所以线程A和线程B就进入了死锁状态。

避免线程

避免死锁,只需要破坏掉至少一个构造死锁的必要条件即可,但是,目前只有持有并请求和环路等待条件是可以被破坏的。

1.破坏环路等待条件

public class DeadLock{
    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 exception){
                        exception.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 (resourceA){
                    System.out.println(Thread.currentThread() + "get resourceB!");
                    try {
                        Thread.sleep(1000);
                    }catch (InterruptedException exception){
                        exception.printStackTrace();;
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceA!");
                    synchronized (resourceB){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                    }
                }
            }
        });

        threadA.start();
        threadB.start();

    }
}

输出:

2.破坏持有并请求条件

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 {
                        resourceA.wait(1000);
                    }catch (InterruptedException exception){
                        exception.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 {
                        resourceB.wait(1000);
                    }catch (InterruptedException exception){
                        exception.printStackTrace();;
                    }
                    System.out.println(Thread.currentThread() + "waiting get resourceA!");
                    synchronized (resourceA){
                        System.out.println(Thread.currentThread() + "get resourceA!");
                    }
                }
            }
        });

        threadA.start();
        threadB.start();

    }
}

注意:不推荐使用,wait()时间太长,就会浪费资源,太短则可能不能够避免死锁!

参考:<<Java 并发编程之美>>

posted on 2020-08-17 11:20  一骑红尘妃子笑!  阅读(251)  评论(0)    收藏  举报