多线程死锁问题 +案例

多线程死锁问题:

一、什么是死锁和原因?

死锁的四个条件:(互斥、不可剥夺、请求持有、循环等待)

最根本原因是:线程在获得一个锁L1的情况下再去申请另外一个锁L2,也就是锁L1想要包含了锁L2,也就是说在获得了锁L1,并且没有释放锁L1的情况下,又去申请获得锁L2,这个是产生死锁的最根本原因**。另一个原因是**默认的锁申请操作是阻塞的。

二、手写一个java多线程的死锁案例?

案例1:锁定类变量(静态变量)

package cetcocean;


/**
 * @description:对两个类变量加锁,导致死锁
 * @author: fangchangtan
 * @create: 2019-04-03 15:10
 * */
public class MultiThreadDeadLock implements Runnable {

    private Object objects1 = new Object();
    private Object objects2 = new Object();
    private boolean flag;

    public static void main(String[] args) {
        Thread thread1 = new Thread(new MultiThreadDeadLock(true),"t1");
        Thread thread2 = new Thread(new MultiThreadDeadLock(false),"t2");
        thread1.start();
        thread2.start();

    }

    public MultiThreadDeadLock(boolean flag ) {
        this.flag =flag;
    }

    @Override
    public void run() {
        while (true) {
            if (flag) {
                synchronized (objects1) {
                    System.out.println("111" + Thread.currentThread().getName() +" lock objects1");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (objects2) {
                        System.out.println("222" + Thread.currentThread().getName() +" lock objects2");
                    }
                }
            } else {
                synchronized (objects2) {
                    System.out.println("222" + Thread.currentThread().getName() +" lock objects2");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (objects1) {
                        System.out.println("111" + Thread.currentThread().getName() +" lock objects1");
                    }
                }
            }


        }

    }
}

运行结果如下:
在这里插入图片描述

内容解释:两个线程分别依次锁定两个类变量,相互挟持自身对象监视器【当前类的监视器】的所而不释放,导致循环等待对方线程释放所需对象的监视器,导致循环等待。最终陷入死循环;

案例2:锁定实例对象的监视器

package cetcocean;

/**
 * @description:锁定两个实例变量的对象监视器,相互等待,导致死锁
 * @author: fangchangtan
 * @create: 2019-04-03 15:31
 * */
public class TestDeadLock {


    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();

        myRunner myRunner1 = new myRunner(obj1, obj2);
        myRunner myRunner2 = new myRunner(obj2, obj1);
        new Thread(myRunner1,"t1").start();
        new Thread(myRunner2,"t2").start();
    }

}

class myRunner implements Runnable {

    private Object obj1;
    private Object obj2;

    public myRunner(Object obj1,Object obj2) {
        this.obj1 = obj1;
        this.obj2 = obj2;

    }

    @Override
    public void run() {
         while (true) {
            synchronized (obj1) {
                System.out.println("111---" + Thread.currentThread().getName() +" ;lock obj: " +obj1);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (obj2) {
                    System.out.println("222***" + Thread.currentThread().getName() +" ;lock obj: "+ obj2);
                }
            }
        }
    }
}



运行结果:

两个线程相互持有对方资源的对象监视器,互不释放,导致多线程循环等待对象释放,导致死锁!

三、避免死锁的方法:在这里插入图片描述

在有些情况下死锁是可以避免的。下面介绍三种用于避免死锁的技术:

  • 加锁顺序(线程按照一定的顺序加锁)

    例如:设计时考虑清楚锁的顺序,尽量减少嵌在的加锁交互数量。

  • 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

    例如:既然死锁的产生是两个线程无限等待对方持有的锁,那么只要等待时间有个上限不就好了。当然synchronized不具备这个功能,但是我们可以使用Lock类中的tryLock方法去尝试获取锁,这个方法可以指定一个超时时限,在等待超过该时限之后便会返回一个失败信息。

  • 死锁检测

展开阅读全文

没有更多推荐了,返回首页