通知和等待对同步块不起作用

时间:2016-04-28 20:18:10

标签: java multithreading synchronization wait notify

此代码是着名的8皇后拼图的不同实现尝试。我尝试使用多线程来完成这项工作。以下代码段是迄今为止的实现。但是有一个问题,wait方法永远等待主线程。我添加了一些SOuts以使测试变得容易,因此它确认它已被卡住了。

主类:

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 个答案:

答案 0 :(得分:1)

代码有几个问题。一个是线程调用&#39; wait()&#39;不是改变数据或阅读它们的人。 与数据交互的线程完全不同步,并且没有使用锁对象。没有人打电话通知()&#39;。

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--

&#34;使当前线程等到另一个线程调用此对象的notify()方法或notifyAll()方法。&#34;

为什么你想要等待()&#39;而不是其他形式的同步?

答案 1 :(得分:1)

我不明白你的代码的逻辑,但这里是我对你的代码的主要评论:

  1. 从不直接致电Thread#run()这是一个常见的错误,不是我们开始Thread的方式,你用Thread#start()启动一个帖子(有道理)没有?)
  2. 即使它看起来很难看,你也应该在synchronized之前的syncOb.wait()块中启动你的线程,以确保主线程在被其他线程通知之前将开始等待,特别是如果任务就像这里的小事。
  3. 使用AtomicInteger作为变量callbacks,因为您需要以原子方式递增它。因此,callbacks=1将替换为callbacks.set(1)callbacks++将替换为callbacks.getAndIncrement()
  4. 您应该在第二个循环中而不是在第一个循环中重置变量callbacks,否则主线程将永远等待,因为通知他的条件永远不会得到满足。