【问题标题】:Notify and wait doesnt work for the sync block通知和等待对同步块不起作用
【发布时间】:2016-04-28 20:18:09
【问题描述】:

此代码是著名的 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();
    }

}

我在这里看不到任何问题,但线程没有唤醒。请有人帮我找出错误。

【问题讨论】:

  • 你没有在这段代码中创建任何线程,使用runRow.start()

标签: java multithreading synchronization wait notify


【解决方案1】:

代码有几个问题。一是调用“wait()”的线程不是进行数据更改或读取数据的线程。 与数据交互的线程是完全不同步的,并且没有使用锁对象。没有人在调用“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--

“使当前线程等待,直到另一个线程为此对象调用 notify() 方法或 notifyAll() 方法。”

为什么要'wait()'而不是其他形式的同步?

【讨论】:

  • 和 callback() 函数正在调用 'notify()'... 是不是错了?
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-12
    • 2015-01-26
    相关资源
    最近更新 更多