Java的重入锁和死锁

时间:2011-06-24 16:33:10

标签: java locking deadlock reentrancy

有人可以通过Java代码(伪)示例向我解释Reentrant lockdeadlock如何相互关联吗?

4 个答案:

答案 0 :(得分:13)

可重入锁定机制允许持有锁的线程重新进入临界区。这意味着您可以执行以下操作:

public synchronized void functionOne() {

    // do something

    functionTwo();

    // do something else

    // redundant, but permitted...
    synchronized(this) {
        // do more stuff
    }    
}

public synchronized void functionTwo() {
     // do even more stuff!
}

在非重入锁定中,当您尝试从functionTwo()调用functionOne()时会出现死锁情况,因为线程必须等待锁定...它自己保留。

当然,死锁是线程1持有锁A并等待锁B而线程2保持锁B并等待锁A的恶劣情况。因此,两者都不能继续。此代码示例创建了一个死锁:

public synchronized void deadlock() throws InterruptedException {
    Thread th = new Thread() {
        public void run() {
            deadlock();
        }
    }.start();

    th.join();
}

调用线程尝试等待生成的线程,然后在调用者退出之前不能调用deadlock()。嘉吊杆!

答案 1 :(得分:6)

发生死锁,然后线程等待永远不会发生的情况。

显而易见的情况是,当您尝试锁定两个锁时,由不同的线程以不同的顺序锁定。

ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();

public void methodA() {
    lock1.lock();
    lock2.lock();
    // do something and un lock both.
}

public void methodB() {
    lock2.lock();
    lock1.lock();
    // do something and un lock both.
}

正如您所看到的,线程可以调用methodA并获取lock1等待lock2,另一个线程调用methodB并获取lock2等待lock1。


但是,线程可能会自行死锁。一个例子是ReentrantReadWriteLock,因为它不支持将读锁升级为写锁。

ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
rwl.readLock().lock();
// do we need to update?
rwl.writeLock().lock(); // will wait for the readLock() to be released!

隐藏锁使用时,一个让自己陷入僵局的难以理解的机会。静态初始化块是隐式线程安全的,因此即使静态初始化块不是synchronized

,也会使用锁定
class A {
     private static int VALUE;
     static {
        Thread t = new Thread() {
            public void run() {
                // waits for the A class to load.
                VALUE = someLongTask();
            }
        };
        t.start();
        // waits for the thread.
        t.join();
    }
}

你又陷入了僵局!

答案 2 :(得分:1)

以下是使用ReentrantLock

的死锁示例
class Deadlock {
    private static final ReentrantLock l1 = new ReentrantLock();

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                System.out.println("A Trying to lock...");
                l1.lock();
                System.out.println("A Locked...");
                try {
                    Thread t = new Thread(new Runnable() {
                        public void run() {
                            System.out.println("B Trying to lock...");
                            l1.lock();
                            System.out.println("B Must not print");
                            try {
                            } finally {
                                System.out.println("B Trying to unlock...");
                                l1.unlock();
                                System.out.println("B Unlocked...");
                            }
                        }
                    });
                    t.start();
                    try {
                        t.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } finally {
                    System.out.println("A Trying to unlock...");
                    l1.unlock();
                    System.out.println("A Unlocked...");
                }
            }
        });
        t.start();
    }
}

要解决死锁问题,请注释掉t.join的来电,同时附上try / catch。

答案 3 :(得分:0)

重入锁定将允许锁定持有者输入代码块,即使它已经通过输入其他代码块获得锁定。一个不可重入的锁将自己拥有锁持有者块,因为它必须释放从另一个代码块获得的锁,以重新获得相同的锁以进入需要代码块的嵌套锁。

就死锁而言,如果从受保护的代码块调用受保护的代码块,您将需要重入锁定(或者在等待自己时会死锁)。