我正在尝试测试一个用例,我需要启动两个线程,但第二个线程需要等待特定状态发生。
第一个线程启动锦标赛的解决过程以计算其时间表。第二个线程停止解析过程。
@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
并且成功了,但我仍然不明白为什么会这样帮助或为什么打印状态会呈现所描述的结果。
最佳答案
getResolutionState()
有什么作用?如果它所做的只是返回您希望其他线程更新的某个变量的值,那么其他线程可能已经已经更新了它,但是更新对其他线程不可见stopResolutionProcessTest()
。
如果线程 A 将某个共享变量设置为新值,Java 语言规范不要求新值立即对任何其他线程可见。事实上,它不需要新值永远变得可见,直到线程同步以某种方式彼此建立所谓的“发生在之前”的关系。
您可以在 StackOverflow 上找到数以千计的关于“HappensBefore”的问题
影响更新可见性的一个操作是进入或离开同步
block 。 System.out.println(...)
方法使用 synchronized
block ,因此如果调用 println()
以前不可见的更新突然变得可见。
如果 getResolutionState()
只是一个私有(private)变量的简单 getter,那么保证状态变化对其他线程可见的一种方法是将其声明为 volatile
变量。
Java 保证一个线程对 volatile
变量所做的任何更新(连同它对任何其他变量所做的任何其他更新 before 它触及 volatile
) 将对读取相同 volatile
变量的任何其他线程可见。
关于java - 除非打印结果,否则陷入无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38105898/