Java多线程实现数独有效性校验时非确定性输出问题咨询
问题原因
- 逻辑设计缺陷
你当前的SudokuTest类中,只有setGrid()方法在执行完成后会调用allChecked()判断三类校验是否全部完成,setRow()、setCol()方法完成后都没有触发该判断。
三个校验线程的执行顺序是完全随机的:如果Grid线程最先完成校验,此时行、列校验还未结束,allChecked()判断结果为false;后续行、列校验完成后,因为对应的set方法不会调用allChecked(),永远不会触发Main.success()执行,自然就不会打印"win"。 - 线程安全问题
SudokuTest中所有的boolean成员变量没有做任何同步处理,也没有加volatile关键字修饰。在Java内存模型中,线程对共享变量的修改会先存到自己的工作内存,不会立刻同步到主内存,其他线程很可能读取到旧的变量值。就算逻辑上三类校验都已完成,也可能因为可见性问题导致allChecked()判断为false。
修复方案
- 补全逻辑:在
setRow()、setCol()方法的最后都添加allChecked()调用,保证不管哪类线程最后完成校验,都能触发全量完成判断。 - 保证线程安全:给
SudokuTest中所有操作共享变量的方法加synchronized关键字,或者给所有boolean成员变量加volatile修饰,保证变量修改的跨线程可见性,避免竞态条件。
修改后的SudokuTest参考代码
public class SudokuTest { public volatile boolean _rowBad; public volatile boolean _colBad; public volatile boolean _gridBad; public volatile boolean _rowChecked; public volatile boolean _colChecked; public volatile boolean _gridChecked; public SudokuTest(){ } public synchronized void setRow(boolean b) { _rowBad = b; _rowChecked = true; if (b) { Main.end(); } allChecked(); } public synchronized void setCol(boolean b) { _colBad = b; _colChecked = true; if (b) { Main.end(); } allChecked(); } public synchronized void setGrid(boolean b) { _gridBad = b; _gridChecked = true; if (b) { Main.end(); } allChecked(); } public synchronized void allChecked() { if (_gridChecked && _colChecked && _rowChecked) { Main.success(); } } }
内容的提问来源于stack exchange,提问作者Phillip Feldman
相关产品推荐
相关产品推荐

