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

问题描述:

此代码是着名的8皇后难题不同的实施尝试。我试图用多线程为此工作。以下代码段是迄今为止的实现。但有一个问题,等待方法永远等待主线程。我添加了一些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(); 
    } 

} 

我看不出这里有什么问题,但线程没有醒来。请有人帮我弄清楚故障。

+3

您在此代码中未创建任何线程,请使用runRow.start() –

代码有几个问题。一个是调用'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的()方法”。

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

+0

“其他同步”是什么意思?请解释.. –

+0

和callback()函数正在调用'notify()'...是否错误? –

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

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