用 Java 编写一个死锁问题然后解开它

  cheney

    在这篇文章中,我将会写一段创建一个死锁情景的代码,然后再讨论解决这种情况下的解决方案。编写多线程程序的时候避免编写不正确的代码导致死锁总是一个挑战。

    死锁就是这么一种情景,多于两个线程都各自占有着不同的资源锁,同时又都等在别的线程释放资源才能完成自己的工作,于是就产生了死锁。

    下面的例子中,线程-1 拥有资源 A 但是需要资源 B 才能完成流程,同样的线程-2 拥有资源 B ,但是需要资源 A 才能工作 。

    用 Java 实现这种情况:

    package me.gpio;
    
    /**
     * Created by cheney on 2014/11/21.
     */
    public class ResolveDeadLockTest {
    
        public static void main(String[] args) {
            ResolveDeadLockTest test = new ResolveDeadLockTest();
    
            String a = "A";
            String b= "B";
    
            // Thread-1
            Runnable task1 = new Runnable() {
                public void run() {
                    synchronized (b) {
                        try {
                            // Adding delay so that both threads can start trying to
                            // lock resources
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // Thread-1 have A but need B also
                        synchronized (a) {
                            System.out.println("task1 over");
                        }
                    }
                }
            };
    
            // Thread-2
            Runnable task2 = new Runnable() {
                public void run() {
                    synchronized (a) {
                        // Thread-2 have B but need A also
                        synchronized (b) {
                            System.out.println("task2 over");
                        }
                    }
                }
            };
    
            new Thread(task1).start();
            new Thread(task2).start();
        }
    }
    

    这段程序跑起来是没有任何输出的,因为死锁了。
    只需要简单的改变资源的申请顺序就能解决这个问题。

    package me.gpio;
    
    /**
     * Created by cheney on 2014/11/21.
     */
    public class ResolveDeadLockTest {
    
        public static void main(String[] args) {
            ResolveDeadLockTest test = new ResolveDeadLockTest();
    
            String a = "A";
            String b= "B";
    
            // Thread-1
            Runnable task1 = new Runnable() {
                public void run() {
                    synchronized (b) {
                        try {
                            // Adding delay so that both threads can start trying to
                            // lock resources
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // Thread-1 have A but need B also
                        synchronized (a) {
                            System.out.println("task1 over");
                        }
                    }
                }
            };
    
            // Thread-2
            Runnable task2 = new Runnable() {
                public void run() {
                    synchronized (b) {
                        // Thread-2 have B but need A also
                        synchronized (a) {
                            System.out.println("task2 over");
                        }
                    }
                }
            };
    
            new Thread(task1).start();
            new Thread(task2).start();
        }
    }