Nadun Liyanage
Nadun Liyanage

Reputation: 463

Notify and wait doesnt work for the sync block

This code is a different implementation attempt for the famous 8 queen puzzle. I tried to work with multithreading for this. Following code segments are the implementation that have so far. But there is a problem, the wait method waits the main thread forever. I have added some SOuts to make the testing easy so it confirms that it is stuck.

Main Class:

public class MainClass {

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

Queen Class

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();
    }

}

I cannot see anything wrong here but the thread doesn't wake. Please someone help me to figure out the fault.

Upvotes: 0

Views: 57

Answers (2)

Nicolas Filotto
Nicolas Filotto

Reputation: 45015

I don't understand the logic of your code but here are the main remarks that I have regarding your code:

  1. Never call Thread#run() directly it is a common mistake, it is not how we start a Thread, you start a thread with Thread#start() (makes sense no?)
  2. Even if it seems ugly, you should start your threads in the synchronized block before syncOb.wait() in order to be sure that the main thread will start waiting before being notified by the other threads especially if the tasks are smalls like here.
  3. Use an AtomicInteger for your variable callbacks as you need to increment it atomically. So callbacks=1 will be replaced by callbacks.set(1) and callbacks++ will be replaced by callbacks.getAndIncrement().
  4. You should reset the variable callbacks in the second loop instead of in the first one otherwise the main thread will wait for ever as the conditions to notify him will never be met.

Upvotes: 1

Lew Bloch
Lew Bloch

Reputation: 3433

There are several issues with the code. One is that the thread calling 'wait()' is not the one making data changes or reading them. The threads that do interact with the data are completely unsynchronized, and are not using the lock object. No one is calling 'notify()'.

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

"Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object."

Why do you want 'wait()' instead of other forms of synchronization?

Upvotes: 1

Related Questions