Уведомление и ожидание не работает для блока синхронизации

Этот код - другая попытка реализации для знаменитой головоломки 8 королевы. Я пытался работать с многопоточностью для этого. Следующие сегменты кода являются реализацией, которая есть до сих пор. Но есть проблема, метод wait ждет основной поток навсегда. Я добавил несколько SOUT, чтобы облегчить тестирование, чтобы оно подтвердило, что оно застряло.

Основной класс:

public class MainClass {

    public static void main(String[]args)
    {
        Queen.board[1][3]=true;
        Queen queen=new Queen();
        queen.placeNextQueen();
    }
}

Королева Класс

public class Queen {

    private static final Object syncOb=new Object();
    public static boolean[][]board=new boolean[10][10];
    public static int onBoard=0;

    private int callbacks=1;

    Thread runRow;
    Thread runCol;
    Thread runLDiag;
    Thread runRDiag;

    boolean rowSafe=true;
    boolean colSafe=true;
    boolean rDiagSafe=true;
    boolean lDiagSafe=true;

    public Queen()
    {
    }

    public void placeNextQueen()
    {
        final Queen queen=this;
        if(++onBoard<8)
        {
            for(int i=0;i<7;i++)
            {
                System.out.println("*******");
                callbacks=1;
                for(int r=0;r<7;r++)
                {
                    final int finalI = i;
                    final int finalR = r;

                    runRow=new Thread() {
                        @Override
                        public void run() {
                            isRowSafe(queen,finalI);
                        }
                    };

                    runCol=new Thread() {
                        @Override
                        public void run() {
                            isColSafe(queen,finalR);
                        }
                    };
                    runRDiag=new Thread() {
                        @Override
                        public void run() {
                            isRDiagSafe(queen,finalI,finalR);
                        }
                    };
                    runLDiag=new Thread() {
                        @Override
                        public void run() {
                            isLDiagSafe(queen,finalI,finalR);
                        }
                    };

                    try
                    {
                        runRow.run();
                        runCol.run();
                        runRDiag.run();
                        runLDiag.run();
                        synchronized(syncOb) {

                            syncOb.wait();
                            System.out.println("WAIT OVER*****************");
                        }
                        if(rowSafe && colSafe && rDiagSafe && lDiagSafe)
                        {
                            board[i][r]=true;

                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("INNER LOOP OVER*****************");
            }

            System.out.println("TO SHOW BOARD*****************");
            showBoard();

        }
    }

    public void showBoard() {

        System.out.println("SHOW BOARD*****************");
        for(int i=0;i<8;i++)
        {
            System.out.print("|");
            for(int r=0;r<8;r++)
            {
                if(board[i][r])
                {
                    System.out.print("*");
                }
                else
                    System.out.print(" ");
                System.out.print("|");
            }
            System.out.println();
        }
    }

    public void callBack()
    {

        System.out.println("CALLBACK*****************"+rowSafe+" "+colSafe+" "+rDiagSafe+" "+lDiagSafe+" "+callbacks);
        if(callbacks++ ==4||(!rowSafe && !colSafe && !rDiagSafe && !lDiagSafe))
        {
            runRow.interrupt();
            runCol.interrupt();
            runRDiag.interrupt();
            runLDiag.interrupt();
            synchronized (syncOb) {
                System.out.println("NOTIFY*****************");
                syncOb.notifyAll();
                System.out.println("NOTIFYed*****************");

            }

        }
    }


    public void isRowSafe(Queen q,int row)
    {
        System.out.println("------------ SAFE");
        for(int i=0;i<7;i++)
        {
            System.out.println("----------- LOOP");
            if(board[row][i])
            {
                System.out.println("--------- IF");
                rowSafe= false;
            }
        }
        rowSafe= true;
        q.callBack();
    }

    public void isColSafe(Queen q,int col)
    {
        System.out.println("||||||||| SAFE");
        for(int i=0;i<7;i++)
        {
            System.out.println("||||||||| LOOP");
            if(board[i][col])
            {
                System.out.println("||||||||| IF");
                colSafe = false;
            }

        }
        colSafe= true;
        q.callBack();
    }

    public void isRDiagSafe(Queen q,int row, int col)
    {
        int initRow=row;
        int initCol=col;

        System.out.println("////////// SAFE");
        //up diagonal
        if(row!=0)
            for (int i=initRow-1;i>=0;i--)
            {
                System.out.println("///////// UP"+i+","+col);
                if(++col>7)
                {
                    rDiagSafe = true;
                    q.callBack();
                    return;
                }
                if(board[i][col])
                    rDiagSafe= false;
            }

        col=initCol;

        //down diagonal
        if(row!=7)
            for(int i=initRow+1;i<8;i++)
            {
                System.out.println("/////////// DOWN"+i+","+col);
                if(--col<0) {
                    rDiagSafe = true;
                    q.callBack();
                    return;
                }
                if(board[i][col])
                    rDiagSafe= false;
            }

        q.callBack();
    }

    public void isLDiagSafe(Queen q,int row, int col)
    {
        System.out.println("DDDDDDDDDDDDDDD SAFE");
        int initRow=row;
        int initCol=col;

        //up diagonal
        if(row!=0)
            for (int i=initRow-1;i>=0;i--)
            {
                System.out.println("DDDDDDDDDDDDDDD UP");
                if(--col>7) {
                    lDiagSafe = true;
                    q.callBack();
                    return;
                }
                if(board[i][col])
                    lDiagSafe= false;
            }

        col=initCol;

        //down diagonal
        if(row!=7)
            for(int i=initRow+1;i<8;i++)
            {
                System.out.println("DDDDDDDDDDDDDDD DOWN");
                if(++col<0) {
                    lDiagSafe = true;
                    q.callBack();
                    return;
                }
                if(board[i][col])
                    lDiagSafe= false;
            }

        q.callBack();
    }

}

Я не вижу здесь ничего плохого, но нить не просыпается. Пожалуйста, кто-нибудь, помогите мне выяснить вину.

2 ответа

Я не понимаю логику вашего кода, но вот основные замечания, которые у меня есть относительно вашего кода:

  1. Никогда не звони Thread#run() непосредственно это распространенная ошибка, это не то, как мы начинаем Thread, вы начинаете тему с Thread#start() (имеет смысл нет?)
  2. Даже если это кажется уродливым, вы должны начать свои темы в synchronized блок до syncOb.wait() чтобы быть уверенным, что основной поток начнет ждать, пока другие потоки не уведомят его, особенно если задачи небольшие, как здесь.
  3. Используйте AtomicInteger для вашей переменной callbacks как вам нужно увеличить его атомарно. Так callbacks=1 будет заменен на callbacks.set(1) а также callbacks++ будет заменен на callbacks.getAndIncrement(),
  4. Вы должны сбросить переменную callbacks во втором цикле, а не в первом, иначе главный поток будет ждать вечно, так как условия для его уведомления никогда не будут выполнены.

Есть несколько проблем с кодом. Одна из них заключается в том, что поток, вызывающий wait(), не является тем, кто вносит изменения или читает их. Потоки, которые взаимодействуют с данными, полностью не синхронизированы и не используют объект блокировки. Никто не звонит notify().

https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html

"Заставляет текущий поток ждать, пока другой поток не вызовет метод notify() или метод notifyAll() для этого объекта".

Почему вы хотите "wait()" вместо других форм синхронизации?

Другие вопросы по тегам