Java 多线程的非确定性行为

Posted

技术标签:

【中文标题】Java 多线程的非确定性行为【英文标题】:Non-deterministic behavior with Java Multithreading 【发布时间】:2021-11-12 22:51:02 【问题描述】:

我编写了一个简单的程序,用于在 Java 中练习多线程。目标是测试数独解决方案是否有效:行、列或子网格中没有重复的数字。在这一点上,我不在乎条目必须来自 1-9。当数独解法无效时,程序运行良好。当数独解决方案有效时(在同一输入上),程序仅在某些时候有效。具体来说,“win”可能会被打印出来,也可能不会被打印出来。

我的程序通过创建 RowThread、ColumnThread 和 GridThread 来工作。他们每个人都分别检查解决方案是否具有有效的行、列和网格。当一个线程完成检查后,它会调用 SudokuTest 中适当的 setter 方法,如果解决方案无效,它将调用 Main 中的 end 方法。如果线程没有判断出解决方案无效,setter方法会记录行、列或网格已经被检查过,然后调用allChecked方法。 allChecked 检查是否已检查行、列和网格。如果是这样,那么解决方案是有效的,所以它调用 Main.success(),它应该打印“win”。这是我的主要课程:

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 < 9; i++)  //loop fills up a 2d array with the numbers 0-80, a valid solution
            for (int j = 0; j < 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 < _sudoku.length; i++) 
            for(int j = 0; j< _sudoku.length; j++) 
                for (int k = j+1; k< _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 && _colChecked && _rowChecked) 
            Main.success();
        
    


【问题讨论】:

你为什么只在setGrid上打电话给allChecked?如果最后没有调用它会发生什么?使用等待 latch 的主线程怎么样?只有当所有三个线程都调用成功时才会继续? 我不敢相信我错过了。我的程序现在工作正常。非常感谢! @PhillipFeldman 请张贴并接受对您自己的问题的回答,以显示解决方案,为后代着想。 【参考方案1】:

答案:正如 Maarten Bodewes 指出的那样,我的错误是没有在 setCol 和 setRow 中调用 allChecked。

【讨论】:

以上是关于Java 多线程的非确定性行为的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程之~~~线程安全容器的非堵塞容器

Java多线程编程——多线程技能

Java多线程编程——多线程技能

Java 多线程代码行为

Java 多线程编程

Java 多线程编程