有人能向我解释一下在Java代码(伪代码)示例中,Reentrant lock
和deadlock
之间的关系吗?
有人能向我解释一下在Java代码(伪代码)示例中,Reentrant lock
和deadlock
之间的关系吗?
可重入锁机制允许持有锁的线程重新进入临界区。这意味着你可以像这样做:
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!
}
在一个不可重入锁中,当你试图从functionOne()
调用functionTwo()
时,会发生死锁情况,因为线程必须等待自己持有的锁,导致无法继续执行。
死锁通常是这样一种恶劣情形:线程 1 持有锁 A 并等待锁 B,而线程 2 持有锁 B 并等待锁 A。因此,两个线程都无法继续执行。以下示例代码会创建死锁:
public synchronized void deadlock() throws InterruptedException {
Thread th = new Thread() {
public void run() {
deadlock();
}
}.start();
th.join();
}
调用线程试图等待已生成的线程,而生成的线程又不能调用 deadlock()
直到调用者退出。炸裂!
死锁发生在一个线程等待永远不会变为真的条件时。
显而易见的情况是,当您尝试以不同的顺序锁定两个锁时,由不同的线程锁定。
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
public void methodA() {
lock1.lock();
lock2.lock();
// do something and unlock both.
}
public void methodB() {
lock2.lock();
lock1.lock();
// do something and unlock 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!
一种使自己陷入死锁的隐蔽机会是使用隐含锁。静态初始化器块是隐式线程安全的,因此即使静态初始化器块没有同步,也会使用锁。
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();
}
}
你又遇到了死锁!
这是一个使用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块。可重入锁允许锁持有者在已经通过进入其他代码块获得锁之后,再次进入代码块。非可重入锁将会阻塞锁持有者自身,因为它必须释放从另一个代码块获得的锁,以重新获取相同的锁来进入嵌套锁定所需的代码块。
就死锁而言,如果您从受保护的代码块调用另一个受保护的代码块,则需要可重入锁(否则您将在等待自己时发生死锁)。
java.util.concurrent.locks.ReentrantLock
而不是synchronized
块的示例。 - Victor Sorokinsynchronized
块还是ReentrantLock
类,高级概念都是相同的。 - stevevls