Java:Object.wait()导致执行的主线程从测试返回

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,

我正在编写一些测试来驱动我的一个辅助项目的开发,我遇到了一些非常奇怪的Java行为:

@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);
}