Java 的可重入锁和死锁
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6470888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reentrant lock and deadlock with Java
提问by Mat B.
Can someone explain to me how Reentrant lock
and deadlock
relate to each other with Java code (pseudo) example?
能否给我一个人解释如何Reentrant lock
和deadlock
相互关系与Java代码(伪)的例子吗?
回答by stevevls
A reentrant locking mechanism allows the thread holding the lock to re-enter a critical section. This means that you can do something like this:
可重入锁定机制允许持有锁定的线程重新进入临界区。这意味着您可以执行以下操作:
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!
}
In a non-reentrant lock, you would have a deadlock situation when you try to call functionTwo()
from functionOne()
because the thread would have to wait for the lock...which it holds itself.
在不可重入锁中,当您尝试调用functionTwo()
from时会出现死锁情况,functionOne()
因为线程必须等待锁……它自己持有。
Deadlock, of course, is the evil situation in which Thread 1 holds lock A and is waiting for lock B while Thread 2 holds lock B and is waiting for lock A. Thus, neither can continue. This code sample creates a deadlock:
死锁当然是一种邪恶的情况,即线程 1 持有锁 A 正在等待锁 B,而线程 2 持有锁 B 正在等待锁 A。因此,两者都不能继续。此代码示例会造成死锁:
public synchronized void deadlock() throws InterruptedException {
Thread th = new Thread() {
public void run() {
deadlock();
}
}.start();
th.join();
}
The calling thread tries to wait around for the spawned thread, which in turn can't call deadlock()
until the caller has exited. Ka-boom!
调用线程尝试等待生成的线程,而该线程在调用deadlock()
者退出之前无法调用。咔嚓!
回答by Peter Lawrey
A dead lock occur then a thread waits for a condition which will never occur.
发生死锁,然后线程等待永远不会发生的条件。
The obvious case is when you are trying to lock two locks, locked in a different order by different threads.
明显的情况是当您试图锁定两个锁时,不同的线程以不同的顺序锁定。
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.
}
As you can see it is possible for a thread to call methodA and obtain lock1 waiting for lock2, and another thread to call methodB and obtain lock2 waiting for lock1.
正如您所看到的,一个线程可以调用 methodA 并获取 lock1 等待 lock2,而另一个线程调用 methodB 并获取 lock2 等待 lock1。
However, it possible for a thread to deadlock itself. An example is ReentrantReadWriteLock because it doesn't support upgrading a read lock to write lock.
但是,线程可能会自己死锁。一个例子是 ReentrantReadWriteLock,因为它不支持将读锁升级为写锁。
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
rwl.readLock().lock();
// do we need to update?
rwl.writeLock().lock(); // will wait for the readLock() to be released!
An obscure opportunity to deadlock yourself is when implied locks are using. A static initialiser block is implicitly thread safe so a lock is used even though static initialiser blocks are not synchronized
当使用隐含锁时,一个让自己陷入死锁的隐晦机会是。静态初始化块是隐式线程安全的,因此即使没有静态初始化块也使用锁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();
}
}
Again you have a deadlock!
你又陷入了僵局!
回答by Victor Sorokin
Here's an example of deadlock with ReentrantLock
这是 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();
}
}
To resolve deadlock, comment out call to t.join
, along with enclosing try/catch.
要解决死锁,请注释掉对 的调用t.join
以及封闭的 try/catch。
回答by Edwin Buck
A reentrant lock will allow the lock holder to enter blocks of code even after it has already obtained the lock by entering other blocks of code. A non-reentrant lock would have the lock holder block on itself as it would have to release the lock it obtained from another block of code to reobtain that same lock to enter the nested lock requiring block of code.
可重入锁将允许锁持有者输入代码块,即使它已经通过输入其他代码块获得了锁。不可重入锁将拥有锁持有者块,因为它必须释放从另一个代码块获得的锁才能重新获得相同的锁才能进入需要代码块的嵌套锁。
As far as deadlock is concerned, if you call a protected block of code from a protected block of code, you'll want a reentrant lock (or you will deadlock while waiting on yourself).
就死锁而言,如果您从受保护的代码块调用受保护的代码块,您将需要一个可重入锁(否则您将在等待自己时死锁)。