Недетерминированное поведение с многопоточностью Java

#java #multithreading #undefined-behavior #sudoku #non-deterministic

Вопрос:

Я написал простую программу, которую использую для практики многопоточности на Java. Цель состоит в том, чтобы проверить, является ли решение судоку верным: никаких повторяющихся чисел в строках, столбцах или подсетях. На данный момент мне все равно, что записи должны быть от 1 до 9. Программа отлично работает, когда решение судоку неверно. Когда решение судоку действительно (на том же входе), программа работает только иногда. В частности, «победа» может быть напечатана, а может и не быть напечатана.

Моя программа работает, создавая поток строк, поток столбцов и поток сетки. Каждый из них проверяет, имеет ли решение допустимые строки, столбцы и сетки соответственно. Когда поток завершает проверку, он вызывает соответствующий метод настройки в SudokuTest, который вызовет метод end в Main, если решение неверно. Если поток не определит, что решение неверно, метод установщика запишет, что строка, столбец или сетка были проверены, а затем вызовет метод allChecked. Все проверено проверяет, были ли проверены строка, столбец и сетка. Если это так, то решение действительно, поэтому оно вызывает Main.success(), который должен вывести «победа». Вот мой основной урок:

 public class Main{  public static void end(){//called by SudokuTest when the solution is invalid  System.out.println("fail");  System.exit(0);  }  public static void success() {//called by SudokuTest when the solution is valid  System.out.println("win");/*this line will not always print,  but it is reached in the debugger when I set a breakpoint.*/  System.exit(0);  }   public static void main(String[] args) {  int[][] sudokuSolution = new int[9][9];  int k = 0;  for (int i = 0; i lt; 9; i  ) { //loop fills up a 2d array with the numbers 0-80, a valid solution  for (int j = 0; j lt; 9; j  ) {  sudokuSolution[i][j] = k;  k  ;  }  }  //sudokuSolution[1][1] = 0;//Testing an invalid solution    SudokuTest t = new SudokuTest();//  Runnable r = new RowThread(sudokuSolution, t);  Runnable c = new ColumnThread(sudokuSolution, t);  Runnable g = new GridThread(sudokuSolution, t);  new Thread(r).start();  new Thread(c).start();  new Thread(g).start();   } }   

Мой класс RowThread:

  public class RowThread implements Runnable {  int[][] _sudoku;  SudokuTest _t;  public RowThread(int[][] sudoku, SudokuTest t) {  _sudoku = sudoku;  _t = t;  }  private void isFail() { //issue: how to get this info back to my Main function?  for(int i = 0; i lt; _sudoku.length; i  ) {  for(int j = 0; jlt; _sudoku.length; j  ) {  for (int k = j 1; klt; _sudoku.length; k  ) {  if (_sudoku[i][j] == _sudoku[i][k]) {  _t.setRow(true);  return;  }  }  }  }  _t.setRow(false);  }   @Override  public void run() {  isFail();  } }   

Мои классы ColumnThread и GridThread совпадают с классами RowThread, за исключением логики в методе isFail (). Мой самый крутой класс:

 public class SudokuTest {  public boolean _rowBad;  public boolean _colBad;  public boolean _gridBad;  public boolean _rowChecked;  public boolean _colChecked;  public boolean _gridChecked;  public SudokuTest(){   }  public void setRow(boolean b) {  _rowBad = b;  _rowChecked = true;  if (b) {  Main.end();  }  }  public void setCol(boolean b) {  _colBad = b;  _colChecked = true;  if (b) {  Main.end();  }  }  public void setGrid(boolean b) {  _gridBad = b;  _gridChecked = true;  if (b) {  Main.end();  }  allChecked();  }  public void allChecked() {  if (_gridChecked amp;amp; _colChecked amp;amp; _rowChecked) {  Main.success();  }  } }   

Комментарии:

1. Почему вы звоните allChecked только по setGrid телефону ? Что произойдет, если он не будет назван последним? Как насчет использования основного потока, который ожидает защелки , которая продолжается только тогда, когда все три потока вызвали успех?

2. Не могу поверить, что я это пропустил. Теперь моя программа работает нормально. Большое Вам спасибо!

3. @PhillipFeldman Пожалуйста, опубликуйте и примите ответ на свой собственный вопрос, показывающий решение, ради потомков.

Ответ №1:

Ответ: как указал Мартен Бодевес, моей ошибкой было не вызывать allChecked в setCol и setRow.