2012-04-11 19 views
0

Javaマルチスレッドサンプルコードをテストしていますが、qB.start()のforループで開始されたスレッドはqBモニターのエントリを待っているためブロックされています。この閉塞の原因は何ですか?このスレッドのブロック問題を解決するには

ありがとうございます。

import java.util.*; 

class QA { 

public synchronized void open() throws Exception { 

    Thread o = new Thread() { 

     public void run() { 

      QB qB = new QB(); 

      qB.start(); 
     } 
    }; 

    o.start(); 
} 

public static void main(String args[]) throws Exception { 

    new QA().open(); 
} 

public class QB { 

private boolean shutdown; 
private Vector<Thread> tList; 
private final Object waitingLock = new Object(); 

public QB() { 

    tList = new Vector<Thread>(); 
} 

public synchronized void start() { 


    for(int i = 0; i < 1; i++) { 

     final int id = i; 

     Thread t = new Thread("Thread " + id) { 

      public void run() { 

       load(id); 
      } 
     }; 

     tList.add(i, t); 

     t.start(); 

    } 

    tMonitor(); 
    waitUntilFinished(); 
} 

private void tMonitor() { 

    Thread cmt = new Thread("T Monitor Thread") { 

     public void run() { 

      synchronized(waitingLock) { 

       while(tList.size() > 0) { 

        try { 

         sleep(10000); 

        } catch(Exception e) { 

         e.printStackTrace(); 
        } 
       } 

       waitingLock.notifyAll(); 
      } 
     } 
    }; 

    cmt.start(); 
} 

private void waitUntilFinished() { 

    synchronized(waitingLock) { 

     while(!isShutDown()) { 

      try { 


       waitingLock.wait(); 


      } catch(Exception e) { 

     e.printStackTrace(); 
      } 
     } 
    } 

} 

private synchronized void load(int id) { 

    try { 

     System.out.println("blocked here"); 

// some work done here 

removeFromTList(id); 


    } catch(Exception e) { 

     e.printStackTrace(); 
    } 
} 


public synchronized boolean isShutDown() { 

    return shutdown; 
} 
} 
} 
+0

もう一度@johnの 'removeFromTList'のコードを見ることができます。 – Gray

+0

public synchronized void removeFromTList(int pos){ tList.removeElementAt(pos); } – John

+0

ええ、そのコードに問題があります。私の答えを見てください。 – Gray

答えて

3

私が見る最初の問題は、QBのインスタンスでQB#start()が同期されていることです。 tのスレッド内に、load(id)も同じインスタンスで同期されます(QB)。だからt.start()tのスレッドブロックを呼び出すとQB#start()まで終了します。

おそらく、QB#start()方法の終わりに、QB#waitUntilFinished()はすべてtスレッドが終了するのを待つことになっているが、彼らはまだ解放するQB#start()方法を待っているので、彼らもQB#load方法を入力することはできませんQBインスタンスのロック

したがって、循環デッドロックです。

+0

いいです。私は他の4つのバグと不足しているコードに集中していました。 – Gray

+0

この問題を解決するにはどうすればよいと思いますか? – John

+0

「同期」ブロック内にできるだけ少なくするという経験則に従ってください。したがって、あなたの場合、 'tList'はあなたの唯一の共有リソースであるため、' synchronized'メソッドを使う代わりに 'tList'のすべての' tList'オペレーションを同期させることができます。 – trutheality

1

編集:

[OK]を、今、私たちはスレッドがバグが完全に明らかにされてtListから削除されている方法を見ていること。

インデックス0のスレッドが最初に終了した場合は、それ自体がリストから削除されます。つまり、インデックス1スレッドが終了すると、Vectorから1番目の位置が削除されますが、それはもはやそれ自身を指していません。 #2スレッドを削除しています。遅かれ早かれ、無効なインデックスを削除しようとしているので、削除が発生したときに例外が発生します。あなたが位置によってアドレスでVectorから項目を削除しないようにする必要があります

tList.remove(this); 

リストから、現在のスレッドを削除します。また、単にadd(t)の代わりに、スタートループ内add(i t)行う必要があります。

tList.add(t); 

あなたは今では、すべてのスレッドに渡されたIDの位置を必要としません。


tListから完成したスレッドを削除する場所は表示されません。 removeFromTList()メソッドの定義(OPを編集したものではない)が表示されますが、どこにも使用されていません。

 while(tList.size() > 0) { 
      try { 
       sleep(10000); 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     // you never get to this line 
        waitingLock.notifyAll(); 

しかし、私は、リストからスレッドを削除何も表示されません。tMonitorでは、ここでは、whileループです。たぶん、スレッドがそれぞれ終了するときに、自分自身を削除するはずですか?

tMonitorスレッドがそのループから抜けることがない場合、それを呼び出したことがない:

waitingLock.notifyAll(); 

だから、メインスレッドがwaitUntilFinished();に永遠にハングします。あなたは​​ブロック内にあるため、

synchronized(waitingLock) { 
    while(!isShutDown()) { 
     try { 
      waitingLock.wait(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

また、あなたはtMonitor()sleepを行うにはしたくありません。

waitingLock.wait(10000); 

これまでに通知するものはありませんが、睡眠中にそのようなロックを保持するのは悪いフォームです。

+0

申し訳ありませんが私はその部分を残しましたが、私はその部分を含めましたが、問題はまだ残っています。 – John

+0

あなたは 'removeFromTlist' @ johnをどこで呼びますか? – Gray

+0

ロード(id)メソッド – John

関連する問題