我正在尝试测试一个需要启动两个线程的用例,但第二个需要等待特定状态发生。
第一个线程启动锦标赛的解决过程以计算其日程安排。第二个线程停止解决过程。
@Test
public void stopResolutionProcessTest() throws InterruptedException {
TournamentSolver solver = tournament.getSolver();
Thread solveThread = new Thread(tournament::solve);
solveThread.start();
while (solver.getResolutionState() != TournamentSolver.ResolutionState.COMPUTING);
Thread stopThread = new Thread(solver::stopResolutionProcess);
stopThread.start();
solveThread.join();
stopThread.join();
assertEquals(TournamentSolver.ResolutionState.INCOMPLETE, solver.getResolutionState());
}
主线程卡在while
循环中,好像它是无限的。
但是,如果我只是在循环内打印分辨率状态,则测试按预期运行:
while (solver.getResolutionState() != TournamentSolver.ResolutionState.COMPUTING)
System.out.println(solver.getResolutionState());
我对此没有任何解释;我觉得自己过去几年回来的时候,我正在学习并发和意想不到的事情,我无法解释。
有人可以了解一下发生了什么吗?
编辑好吧我将我的getResolutionState()
设置为synchronized
并且这样做了,但我仍然不明白为什么这会有所帮助或为什么打印州将呈现所描述的结果。
答案 0 :(得分:1)
getResolutionState()
做什么?如果它正在做的只是返回你希望另一个线程更新的某个变量的值,那么另一个已经的线程可能更新了它,但是更新没有变得可见stopResolutionProcessTest()
。
如果线程A将某个共享变量设置为新值,则Java语言规范不要求新值立即对任何其他线程可见。实际上,它不需要永远的新值,直到线程以某种方式彼此同步以建立所谓的“之前发生”关系。
您可以在StackOverflow上找到数千个关于“HappensBefore”
的问题影响更新可见性的一项操作是进入或离开synchronized
块。 System.out.println(...)
方法使用synchronized
块,因此如果调用println()
突然变得可见,那么毫不奇怪。
如果getResolutionState()
只是私有变量的简单getter,那么保证状态更改对其他线程可见的一种方法是将其声明为volatile
变量。
Java保证一个线程对volatile
变量所做的任何更新(以及它在触及volatile
之前对任何其他变量所做的任何其他更新)将对任何其他读取相同volatile
变量的线程可见。