Java:Object.wait()导致执行的主线程从测试返回
我正在编写一些测试来驱动我的一个辅助项目的开发,我遇到了一些非常奇怪的Java行为:Java:Object.wait()导致执行的主线程从测试返回,java,multithreading,Java,Multithreading,我正在编写一些测试来驱动我的一个辅助项目的开发,我遇到了一些非常奇怪的Java行为: @Test public void testSendReceiveAll() throws Exception { for (String s : (ArrayList<String>)testFiles) { ((FakeSendFileApi) sendFileApi).setSender(new InetSocketAddress(LOCALHOST,
@Test
public void testSendReceiveAll() throws Exception {
for (String s : (ArrayList<String>)testFiles) {
((FakeSendFileApi) sendFileApi).setSender(new InetSocketAddress(LOCALHOST,
LOCALPORT)).setIncomingFileName(s + incrAppend());
PendingFile pendingFile = new PendingFile(TEST_PATH + s, new InetSocketAddress(LOCALHOST,
LOCALPORT));
SendAction sendAction = new SendAction(pendingFile);
Thread sendActionThread = new Thread(sendAction);
synchronized (sendAction){
sendActionThread.start();
sendAction.wait(TIMEOUT_MS);
}
File file = new File(s + fileAppend);
assertTrue(file.exists());
assertTrue(file.isFile());
assertTrue(file.canRead());
assertTrue(file.delete());
}
}
Object.wait()使执行主线程返回并跳过以下所有执行行,但仅在循环中第二次调用它。
我之所以知道这一点,是因为我试图在不使用Thread.sleep()的情况下编写测试,因为我认为在执行的主线程中插入这些测试通常是不好的做法,尤其是那些以后会扩展并成为非常长时间运行的任务的测试
这是我的测试:
@Test
public void testSendReceiveAll() throws Exception {
for (String s : (ArrayList<String>)testFiles) {
((FakeSendFileApi) sendFileApi).setSender(new InetSocketAddress(LOCALHOST,
LOCALPORT)).setIncomingFileName(s + incrAppend());
PendingFile pendingFile = new PendingFile(TEST_PATH + s, new InetSocketAddress(LOCALHOST,
LOCALPORT));
SendAction sendAction = new SendAction(pendingFile);
Thread sendActionThread = new Thread(sendAction);
synchronized (sendAction){
sendActionThread.start();
sendAction.wait(TIMEOUT_MS);
}
File file = new File(s + fileAppend);
assertTrue(file.exists());
assertTrue(file.isFile());
assertTrue(file.canRead());
assertTrue(file.delete());
}
}
问题:当我点击测试的synchronized块,启动要发送的线程,然后等待来自sendAction的通知时,这在循环中第一次起作用但是,第二次通过时,该测试在调用
sendAction.wait(TIMEOUT_MS);
这只会在某些时候发生,而不会在其他时候发生。我放置了print语句,以查看是否可以在不进行调试的情况下实现竞争条件,它确实发送和接收第一个文件,但并不总是发送和接收第二个文件。当我在sendAction.wait(TIMEOUT_MS)之后放置println()语句时;调用时,它不会在第二次循环迭代后执行
什么给了???等待应该总是在循环中发生。(有关更多详细信息,请参阅Object.wait()的javadoc) 维护标志以标记任务的完成,并在保护sendAction.wait()的条件中使用它
在调用notifyAll()之前,将“sendAction.finished”设置为true。。。最后执行此操作。我看不到您在run()中关闭套接字或其流。您的方法在执行
wait
之后肯定不会返回。它突然完成,抛出一个异常。最好找出那个例外是什么。否则,如果没有异常,那么它只会继续执行那些断言语句。顺便说一句,如果子线程中出现异常,则会出现死锁(在您的情况下,最终会超时)。您应该在finally
中通知所有人
。而且,不用说,您正在对其合同使用等待
。您必须始终实现等待循环习惯用法。此外,如果您的代码打算等待线程完成,则应该使用“join”而不是“wait”。虽然您的答案通常是好的建议,但它并不是这个问题的答案。不会发生虚假唤醒,因为在wait()调用之后,如果是这种情况,执行将继续。
while(!sendAction.finished) {
sendAction.wait(TIMEOUT_MS);
}