LiT*_*Tle 5 java testing concurrency multithreading blocking
根据清单12.3中的Java Concurrency in Practice书,我们可以使用以下示例代码测试并发代码:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
假设执行了以下步骤:
taker 线程启动。bb.take()成功返回,我们只需要一点点fail()方法就可以运行。interrupt()方法。catch障碍中taker。因此,我们目前处于困境,但实际上测试方法失败了。它失败了,我们从不知道。
这是正确的吗?如果是,我们该如何解决?
take应该阻塞在空队列上。所以预期的事件顺序是:
taker.start();=> 启动线程Thread.sleep(LOCKUP_DETECT_TIMEOUT);等待以确保线程已启动并take已被调用。常量的实际值很难估计,但是任何高于几百毫秒的值都应该足够了 - 或者,您可以使用 CountDownLatch 来了解接受者线程何时启动bb.take();=> 应该被阻止 - 如果不fail()被调用并且测试失败taker.interrupt();=> 该take()方法应该退出InterruptedExceptiontaker.join();=> 等待一段时间以允许接受者线程完成assertFalse(taker.isAlive());=> 确认接受者线程已经退出并且不再被阻塞在take方法中带闩锁的版本(假设如果线程在调用之前 被中断,则会以 InterruptedException 退出 - 如果不是,那么你没有其他方法,只能在调用之前添加一些随机睡眠):taketakestarted.await()
void testTakeBlocksWhenEmpty() {\n final CountDownLatch started = new CountDownLatch(1);\n final CountDownLatch ended = new CountDownLatch(1);\n final BoundedBuffer<Integer> bb = new BoundedBuffer<Integer>(10);\n Thread taker = new Thread() {\n public void run() {\n try {\n started.countDown();\n int unused = bb.take();\n fail(); // if we get here, it\xe2\x80\x99s an error\n } catch (InterruptedException success) { }\n ended.countDown();\n }\n };\n try {\n taker.start();\n started.await();\n taker.interrupt();\n assertTrue(ended.await());\n } catch (Exception unexpected) {\n fail();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n您应该向测试方法或锁存器添加超时(足够长,以便在测试通过时不会干扰,例如 5 秒)。这将避免阻塞您的整个测试套件。
\n