java并发之死锁

上一篇博客 java并发之加锁中主要介绍了在数据库中的加锁问题,现在来聊聊Java中会出现的死锁。
关于死锁,一般教科书的都会罗列满足死锁的几个概念,如互斥、竞态条件等,今天从代码里直接去看死锁,或许会更加直观,直捣黄龙,比记住概念要强得多。


/**
 * @author Jerry
 */
public class ThreadDeadlock {

    public static void main(String[] args) throws InterruptedException {
        Object obj1 = new MyObject("lockA");//这里是几个锁,为下面三个线程共同来争取
        Object obj2 =  new MyObject("lockB");
        Object obj3 = new MyObject("lockC");

        Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1"); //三个线程,注意三个线程加锁的顺序,会形成闭环
        Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
        Thread t3 = new Thread(new SyncThread(obj3,obj1), "t3");

        t1.start();
        Thread.sleep(5000);
        t2.start();
        Thread.sleep(5000);
        t3.start();

    }

}
class MyObject{
    private String name;

    public MyObject(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}
class SyncThread implements Runnable{
    private Object obj1;
    private Object obj2;

    public SyncThread(Object o1, Object o2){
        this.obj1=o1;
        this.obj2=o2;
    }
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " acquiring lock on "+obj1);
        synchronized (obj1) {
            System.out.println(name + " acquired lock on "+obj1);
            work();
            System.out.println(name + " acquiring lock on "+obj2);
            synchronized (obj2) {//要形成死锁,这里的锁获取要形成嵌套,才会让线程既拥有一个锁又想再去获取另一个
                System.out.println(name + " acquired lock on "+obj2);
                work();
            }
            System.out.println(name + " released lock on "+obj2);
        }
        System.out.println(name + " released lock on "+obj1);
        System.out.println(name + " finished execution.");
    }
    private void work() {
        try {
            Thread.sleep(20000);//模拟耗时操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

最后这里运行结果如下,程序不会终止,没有一个线程释放了锁,线程之间在相互等待,形成了死锁阻塞。

t1 acquiring lock on lockA
t1 acquired lock on lockA
t2 acquiring lock on lockB
t2 acquired lock on lockB
t3 acquiring lock on lockC
t3 acquired lock on lockC
t1 acquiring lock on lockB
t2 acquiring lock on lockC
t3 acquiring lock on lockA

我们如果稍微修改一下代码,将原本 Thread t3 = new Thread(new SyncThread(obj3,obj1), “t3”);
替换成 Thread t3 = new Thread(new SyncThread(obj1,obj3), “t3”);
这样运行的结果如下,可以看出程序不形成死锁,已正常关闭。

t1 acquiring lock on lockA
t1 acquired lock on lockA
t2 acquiring lock on lockB
t2 acquired lock on lockB
t3 acquiring lock on lockA
t1 acquiring lock on lockB
t2 acquiring lock on lockC
t2 acquired lock on lockC
t2 released lock on lockC
t2 released lock on lockB
t2 finished execution.
t1 acquired lock on lockB
t1 released lock on lockB
t1 released lock on lockA
t1 finished execution.
t3 acquired lock on lockA
t3 acquiring lock on lockC
t3 acquired lock on lockC
t3 released lock on lockC
t3 released lock on lockA
t3 finished execution.

或者我们将锁获取方式由嵌套换成一次获取,也就是每次只是持有一个锁,也会得到如上的结果。

syn(lock1){                         syn(lock1){}
    syn(lock2){                     syn(lock2){}
    }
}   

所以避免死锁可以通过每次只获取一个锁或者依次获取锁来避免死锁的问题,当然也可以通过一些超时设定机制来强制退出,解决死锁问题。

猜你喜欢

转载自blog.csdn.net/jerryJavaCoding/article/details/78884627