2016-04-28 43 views
0

此代碼是着名的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() –

回答

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的()方法」。

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

+0

「其他同步」是什麼意思?請解釋.. –

+0

和callback()函數正在調用'notify()'...是否錯誤? –

1

我不明白你的代碼的邏輯,但這裏是主要的言論,我對自己的代碼:

  1. 決不呼叫Thread#run()直接是一個常見的錯誤,這是不是我們開始Thread,你啓動一個線程與Thread#start()(有道理沒有?)
  2. 即使它看起來醜陋,你應該在​​塊爲了啓動線程syncOb.wait()之前,以確保主線程將開始爲之前等待由其他線程通知尤其特別是如果任務是像這裏一樣小的話。
  3. 使用AtomicInteger作爲變量callbacks,因爲您需要以原子方式增加它。所以callbacks=1將被替換爲callbacks.set(1)callbacks++將被替換爲callbacks.getAndIncrement()
  4. 您應該在第二個循環而不是第一個循環中重置變量callbacks,否則主線程將一直等待,因爲通知他的條件永遠不會被滿足。