使用 CountDownLatch 测试强制竞争条件导致 java.lang.IllegalMonitorStateException
Test to force a race condition using CowntDownLatch causes java.lang.IllegalMonitorStateException
我试图创建一个测试,我试图强制竞争条件(或至少增加其发生的可能性)并且我使用了 CountDownLatch
.
问题是我的 CountDownLatch.wait()
得到了一个 java.lang.IllegalMonitorStateException
。我肯定在滥用 CountDownLatch
并且我肯定没有以巧妙的方式创建此测试。
这个简单的代码重现了我的想法和我的问题(我也有一个gist):
import java.util.*;
import java.util.concurrent.*;
public class Example {
private static BusinessLogic logic;
public static void main(String[] args) {
final Integer NUMBER_OF_PARALLEL_THREADS = 10;
CountDownLatch latch = new CountDownLatch(NUMBER_OF_PARALLEL_THREADS);
logic = new BusinessLogic();
// trying to force the race condition
List<Thread> threads = new ArrayList<Thread>(NUMBER_OF_PARALLEL_THREADS);
for (int i=0; i<NUMBER_OF_PARALLEL_THREADS; i++) {
Thread worker = new Thread(new WorkerRunnable(latch));
threads.add(worker);
worker.start();
}
for (int i = 1; i <= NUMBER_OF_PARALLEL_THREADS; i++) {
try {
threads.get(i).wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Just a dummy business logic class.
* I want to "force" a race condition at the method doSomething().
*/
private static class BusinessLogic {
public void doSomething() {
System.out.println("Doing something...");
}
}
/**
* Worker runnable to use in a Thead
*/
private static class WorkerRunnable implements Runnable {
private CountDownLatch latch;
private WorkerRunnable(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
try {
// 1st I want to decrement the latch
latch.countDown();
// then I want to wait for every other thread to
latch.wait(); // the exception is thrown in this line.
// hopefully increase the probability of a race condition...
logic.doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
CountDownLatch.wait()
的 javadoc 声明如果当前线程不是对象监视器的所有者,则会抛出 IllegalMonitorStateException
。但恐怕我不明白这是什么意思,我也不知道如何重新创建我的代码来避免这个异常。
编辑:根据答案中提供的提示,我创建了上述示例的新版本并存储在 this gist 中。我现在没有任何例外。
您的控制器线程(通常是 main/ui 线程)应该进行等待,而工作线程则进行倒计时。
您应该从主线程启动线程并在其中插入 latch.await()
调用 - 就在您启动它们之后。
每个工作线程应在完成时调用 latch.countdown()
。
当所有线程调用countdown()
时,CountDownLatch 将在主线程中退出latch.await()
,并将执行控制权转移给它(latch.await()
之后的代码将开始执行)。
所以基本上你需要在启动工作线程后立即将 await()
移动到主程序。
编辑:您还应该删除 Thread.wait()
调用,因为那是另一个多线程框架 - wait/notify 并且它比使用 CountDownLatch 低级得多(除非您的模拟需要它.我不太明白你的测试用例)
尝试调用 wait()
任何对象时,您必须拥有该对象的监视器。
Object o = new Object();
o.wait();
会导致 IllegalMonitorStateException
.
您必须同步该对象才能调用 wait()
:
Object o = new Object();
synchronized(o) {
o.wait();
}
await()
将等待直到锁存器达到零。 wait()
与闩锁无关,也不是您想要的 WorkerRunnable
。但是仅供参考,为了调用 wait()
而不会出现异常,您必须拥有一个对象的监视器,并且要成为所有者,您必须位于该对象的 synchronized
块中。
我试图创建一个测试,我试图强制竞争条件(或至少增加其发生的可能性)并且我使用了 CountDownLatch
.
问题是我的 CountDownLatch.wait()
得到了一个 java.lang.IllegalMonitorStateException
。我肯定在滥用 CountDownLatch
并且我肯定没有以巧妙的方式创建此测试。
这个简单的代码重现了我的想法和我的问题(我也有一个gist):
import java.util.*;
import java.util.concurrent.*;
public class Example {
private static BusinessLogic logic;
public static void main(String[] args) {
final Integer NUMBER_OF_PARALLEL_THREADS = 10;
CountDownLatch latch = new CountDownLatch(NUMBER_OF_PARALLEL_THREADS);
logic = new BusinessLogic();
// trying to force the race condition
List<Thread> threads = new ArrayList<Thread>(NUMBER_OF_PARALLEL_THREADS);
for (int i=0; i<NUMBER_OF_PARALLEL_THREADS; i++) {
Thread worker = new Thread(new WorkerRunnable(latch));
threads.add(worker);
worker.start();
}
for (int i = 1; i <= NUMBER_OF_PARALLEL_THREADS; i++) {
try {
threads.get(i).wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Just a dummy business logic class.
* I want to "force" a race condition at the method doSomething().
*/
private static class BusinessLogic {
public void doSomething() {
System.out.println("Doing something...");
}
}
/**
* Worker runnable to use in a Thead
*/
private static class WorkerRunnable implements Runnable {
private CountDownLatch latch;
private WorkerRunnable(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
try {
// 1st I want to decrement the latch
latch.countDown();
// then I want to wait for every other thread to
latch.wait(); // the exception is thrown in this line.
// hopefully increase the probability of a race condition...
logic.doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
CountDownLatch.wait()
的 javadoc 声明如果当前线程不是对象监视器的所有者,则会抛出 IllegalMonitorStateException
。但恐怕我不明白这是什么意思,我也不知道如何重新创建我的代码来避免这个异常。
编辑:根据答案中提供的提示,我创建了上述示例的新版本并存储在 this gist 中。我现在没有任何例外。
您的控制器线程(通常是 main/ui 线程)应该进行等待,而工作线程则进行倒计时。
您应该从主线程启动线程并在其中插入 latch.await()
调用 - 就在您启动它们之后。
每个工作线程应在完成时调用 latch.countdown()
。
当所有线程调用countdown()
时,CountDownLatch 将在主线程中退出latch.await()
,并将执行控制权转移给它(latch.await()
之后的代码将开始执行)。
所以基本上你需要在启动工作线程后立即将 await()
移动到主程序。
编辑:您还应该删除 Thread.wait()
调用,因为那是另一个多线程框架 - wait/notify 并且它比使用 CountDownLatch 低级得多(除非您的模拟需要它.我不太明白你的测试用例)
尝试调用 wait()
任何对象时,您必须拥有该对象的监视器。
Object o = new Object();
o.wait();
会导致 IllegalMonitorStateException
.
您必须同步该对象才能调用 wait()
:
Object o = new Object();
synchronized(o) {
o.wait();
}
await()
将等待直到锁存器达到零。 wait()
与闩锁无关,也不是您想要的 WorkerRunnable
。但是仅供参考,为了调用 wait()
而不会出现异常,您必须拥有一个对象的监视器,并且要成为所有者,您必须位于该对象的 synchronized
块中。