我想在Java线程并发中创建竞争条件并创建死锁。 我使用ReentrantLock,但它不会抛出InterruptedException。
现在是死锁,我使用lockInterruptibly,但它不会抛出InterruptedException,任何机构都可以告诉我为什么?
public class Test {
public static void main(String[] args) throws InterruptedException {
final Object o1 = new Object();
final Object o2 = new Object();
final ReentrantLock l1 = new ReentrantLock();
final ReentrantLock l2 = new ReentrantLock();
Thread t1 = new Thread() {
public void run() {
try {
l1.lockInterruptibly();
System.out.println("I am in t1 step 1 " + o1.toString());
Thread.sleep(1000);
l2.lock();
try {
System.out.println("I am in t1 step 2 " + o2.toString());
} finally {
l2.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread() {
public void run() {
try {
l2.lockInterruptibly();
System.out.println("I am in t2 step 1 " + o2.toString());
Thread.sleep(1000);
l1.lock();
try {
System.out.println("I am in t2 step 2 " + o1.toString());
} finally {
l1.unlock();
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
};
t1.start();
t2.start();
Thread.sleep(2000);
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
}
}
答案 0 :(得分:1)
2个帖子在行中l1.lock()
和l2.lock()
处于死锁状态。所以当你打断他们时他们没有反应。如果您使用lock()
替换所有lockInterruptibly()
来电,您将获得例外。
编辑: 我准备了更简单的例子,可以根据需要生成竞争条件:
public class Test {
public static void main(String[] args) throws InterruptedException {
final ReentrantLock l1 = new ReentrantLock();
final Random rn = new Random();
Thread t1 = new Thread() {
public void run() {
try {
Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms
l1.lockInterruptibly();
System.out.println("Thread 1 won");
} catch (InterruptedException e) {
System.out.println("Thread 1 interrupted");
}
}
};
Thread t2 = new Thread() {
public void run() {
try {
Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms
l1.lockInterruptibly();
System.out.println("Thread 2 won");
} catch (InterruptedException e1) {
System.out.println("Thread 2 interrupted");
}
}
};
t1.start();
t2.start();
Thread.sleep(2000);
t1.interrupt();
t2.interrupt();
t1.join();
t2.join();
}
}
使用此代码,每次运行时,您将随机获得两个输出中的一个:
Thread 1 won
Thread 2 interrupted
或
Thread 2 won
Thread 1 interrupted
取决于生成的随机数。
答案 1 :(得分:1)
你的问题是每个线程都试图接受两个锁。
// Thread 1.
l1.lockInterruptibly();
// ....
l2.lock();
// Thread 2.
l2.lockInterruptibly();
// ....
l1.lock();
所以每个线程抓取一个锁,然后尝试抓住另一个线程已经拥有的锁。这称为死锁。
您没有看到java.lang.InterruptedException
,因为线程正在等待的锁(第二个)不是可中断的锁。
修复此问题:
// Thread 1.
l1.lockInterruptibly();
// ....
l2.lockInterruptibly();
// Thread 2.
l2.lockInterruptibly();
// ....
l1.lockInterruptibly();
答案 2 :(得分:0)
可重入意味着已经拥有锁的单个线程可以重新获得它。
在你的情况下,创建了两个不同的线程。
这称为 Reentrance lockout ,是一种类似于死锁和嵌套监视器锁定的情况。
你可以通过Thread t1
解决这个问题 l1.lockInterruptibly();
System.out.println("I am in t1 step 1 " + o1.toString());
Thread.sleep(1000);
l2.lockInterruptibly();
并在线程t2中
l2.lockInterruptibly();
System.out.println("I am in t2 step 1 " + o2.toString());
Thread.sleep(1000);
l1.lockInterruptibly();
答案 3 :(得分:0)
它不会抛出InterruptedException,任何人都可以告诉我为什么?
也许是因为创建ReentrantLock
的目的是互斥。
如果你的程序中的一个线程持有的互斥锁被锁定超过一小段时间,那就是代码异味。
使lock.lock()
调用可中断会使使用它的所有程序复杂化:每个要锁定锁的地方,都必须为InterruptedException
编写处理程序。
我的猜测(就是这样)是作者认为他们不应该让所有程序员都必须编写那些额外的中断处理程序,以便某些程序员可以使用ReentrantLock
糟糕的设计。