我找不到问题的正确答案。
我将找到一种方法来测试我的代码(使用 JUnit)并在 Eclipse 控制台中查看结果。经过一些调查后发现,线程的 setDaemon(true) 可以正常工作,但控制台中会显示注释。那么,问题来了:
我有一个 Web 服务,它创建一个对象并将其 ID 返回给用户,但我想在 return 语句之后做另一件事。 我使用了一个新线程,但由于我的函数需要时间,首先调用 return 语句,因此新线程(firstThread)永远不会完成!我很感激任何建议。
我不想在我的线程中使用 join(),因为它会阻止用户从 Web 服务获取结果,直到我的工作完成!
这里是示例代码:
@Test
public void tt() {
System.out.println("Start main thread.");
Thread firstThread = new Thread(() -> {
try{
Thread.sleep(500);
}catch(Exception ex) {
ex.printStackTrace();
}
//never saw in eclipse console
System.out.println("First thread is running.");
});
Thread secondThread = new Thread(() -> {
System.out.println("Second thread is running.");
});
try {
firstThread.setDaemon(true); //
secondThread.start();
firstThread.start();
System.out.println("both done");
return;
} catch (Exception e) {
e.printStackTrace();
}
}
在此示例中,我从未看到“第一个线程正在运行”。以下是控制台中出现的输出: 启动主线程。
都完成了
第二个线程正在运行。
单元测试中的多线程有点棘手,因为 jUnit 运行程序只会知道您的主线程,一旦返回,jUnit 运行程序就会认为测试已完成。其他线程可能会继续在后台运行(可能会干扰其他测试),但是一旦执行了最后一个测试,jUnit 就会认为其工作已完成并退出。
所以这里发生的是你的测试方法被启动,它产生两个线程然后返回。 JUnit 只看到已运行且没有任何异常的测试,将测试用例标记为绿色并结束。
通常,在单元测试中使用多个线程时,我会创建某种方法来检查在退出测试之前是否完成了主线程以外的线程。根据我的经验,这主要是集成测试(@SpringBootTest)中的一个问题。
我也有点不确定 System.out.println 当从主线程不再存在的守护线程完成时实际上最终会在哪里,可能是它们最终“无处可去”。
如果您使用 Spring,您应该查看 @Async 注释以简化您的代码。请注意,任何错误都将发生在调用者的“范围”之外,并且不会引人注目,因此您需要格外小心错误处理。使用消息总线可能是确保处理所有调用的一种方法,但也可能有点过头了。使用 Spring 异步,代码应该类似于:
public class WebService {
private SomeAsyncService someAsyncService;
public Something webMethod(final int id) {
final Something something = findSomethingAndDoStuffThatDoesntTakeMuchTime(id);
someAsyncService.doStuffThatTakesALotOfTime(something);
return something;
}
}
public class SomeAsyncService {
@Async
public void doStuffThatTakesALotOfTime(final Something something) {
try {
// do stuff
// can take time
} catch (final Exception e) {
// error handling based on your needs
}
}
}
对于
webMethod
的调用者,只需要等待第一次调用,并在另一笔交易正在执行 doStuffThatTakesALotOfTime
方法时返回。