根据清单12.3中实际使用的Java并发性一书,我们可以使用以下示例代码测试并发代码:
void testTakeBlocksWhenEmpty() {
final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
Thread taker = new Thread() {
public void run() {
try {
int unused = bb.take();
fail(); // if we get here, it’s an error
} catch (InterruptedException success) { }
}
};
try {
taker.start();
Thread.sleep(LOCKUP_DETECT_TIMEOUT);
taker.interrupt();
taker.join(LOCKUP_DETECT_TIMEOUT);
assertFalse(taker.isAlive());
} catch (Exception unexpected) {
fail();
}
}假设执行了以下步骤:
taker线程启动。bb.take()成功返回,我们在fail()方法运行之前就有一点点时间了。interrupt()方法。catch线程的taker块。因此,我们现在在catch块,但实际上测试方法失败了。它失败了,我们从未被告知。
是这样的吗?如果是的话,我们怎么解决这个问题呢?
发布于 2013-10-02 08:43:07
take应该在空队列上阻塞。因此,预期的事件顺序是:
taker.start(); =>启动线程Thread.sleep(LOCKUP_DETECT_TIMEOUT);等待确保线程已启动,并已调用take。常量的实际值很难估计,但是超过几百个millis的值就足够了-或者您可以使用CountDownLatch来知道接收线程何时启动。bb.take(); =>应该阻塞-如果不阻塞,则调用fail(),并且测试失败taker.interrupt(); =>中,take()方法应该与InterruptedException一起退出taker.join(); =>等待一段时间,以允许接收者线程完成。assertFalse(taker.isAlive()); =>确认接受线程已经退出,并且不再在take方法中被阻塞。带有锁存器的版本(它假设如果线程在take调用之前被中断,take将使用InterruptedException退出-如果没有,那么您别无选择,只能在调用started.await()之前添加一些随机睡眠):
void testTakeBlocksWhenEmpty() {
final CountDownLatch started = new CountDownLatch(1);
final CountDownLatch ended = new CountDownLatch(1);
final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);
Thread taker = new Thread() {
public void run() {
try {
started.countDown();
int unused = bb.take();
fail(); // if we get here, it’s an error
} catch (InterruptedException success) { }
ended.countDown();
}
};
try {
taker.start();
started.await();
taker.interrupt();
assertTrue(ended.await());
} catch (Exception unexpected) {
fail();
}
}您应该在测试方法或闩锁中添加一个超时(如果测试通过,时间足够长,例如5秒)。这将避免阻塞您的整个测试套件。
https://stackoverflow.com/questions/19131867
复制相似问题