有人可以通过Java代码(伪)示例向我解释Reentrant lock
和deadlock
如何相互关联吗?
答案 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()
时会出现死锁情况,因为线程必须等待锁定...它自己保留。
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)
重入锁定将允许锁定持有者输入代码块,即使它已经通过输入其他代码块获得锁定。一个不可重入的锁将自己拥有锁持有者块,因为它必须释放从另一个代码块获得的锁,以重新获得相同的锁以进入需要代码块的嵌套锁。
就死锁而言,如果从受保护的代码块调用受保护的代码块,您将需要重入锁定(或者在等待自己时会死锁)。