2016-04-28 7 views
0

このコードは、有名な8つのクイーンパズルの実装方法が異なります。私はこのためにマルチスレッドで作業しようとしました。次のコードセグメントはこれまでの実装です。しかし問題があり、waitメソッドはメインスレッドを永遠に待ちます。私はいくつかのSOUTを追加してテストを簡単にして、スタックされていることを確認します。シンクブロックの通知と待機does doesnt work

メインクラス:

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.2https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--

「は、別のスレッドが通知()メソッド、またはこの目的のためのnotifyAll()メソッドを呼び出すまで、現在のスレッドを待機させます。」

他の形式の同期ではなく、なぜ「待ち」しますか?

+0

「他の同期」とはどういう意味ですか?説明してください。 –

+0

とcallback()関数が 'notify()'を呼び出しています...間違っていますか? –

1

私はあなたのコードについている主な発言あなたのコードのロジックを理解するが、ここではないん

  1. を決してコールThread#run()直接それはよくある間違いでどのように我々、そうではありませんそれは醜いと思われる場合でも、あなたはメインスレッドがされる前に待機して開始することを確認するために、syncOb.wait()前​​ブロックであなたのスレッドを起動する必要があります
  2. (無理にかなっている?)Threadを開始し、あなたがThread#start()でスレッドを開始他のスレッドespによって通知されるタスクがここのような小さなものであれば、それは非常に重要です。
  3. 変数callbacksには、アトミックにインクリメントする必要があるため、AtomicIntegerを使用してください。従ってcallbacks=1callbacks.set(1)に置き換えられ、callbacks++callbacks.getAndIncrement()に置き換えられます。
  4. 変数callbacksを最初のループではなく2番目のループでリセットする必要があります。そうしないと、メインスレッドは、通知する条件が決して満たされないため、永久に待機します。