4

そのため、ネットワークソースからの通信を待機しているコードを少し継承しました。

ネットワークソケットからのデータを待機している間、Thread.sleep(10)が呼び出されます。jconsoleとここでの私のスレッドダンプによって報告されているように、これはスレッドリークを引き起こしているようです(Thread-68、Thread-385などには何百ものエントリがありますが、簡潔にするために短縮しました):

Wed Jan 18 09:14:40 PST 2012
2012-01-18 09:14:50
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b11 mixed mode):

"Thread-69" daemon prio=10 tid=0x00007f01a047c800 nid=0x3725 waiting on condition [0x00007f019eaf4000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at com.unitt.framework.websocket.simple.NetworkSocket.run(NetworkSocket.java:304)
        at java.lang.Thread.run(Thread.java:662)

"Thread-68" daemon prio=10 tid=0x00007f01a0500000 nid=0x371c waiting on condition [0x00007f019ecf6000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at com.unitt.framework.websocket.simple.NetworkSocket.run(NetworkSocket.java:304)
        at java.lang.Thread.run(Thread.java:662)

問題のコード:

public class NetworkSocket implements NetworkSocketFacade, Runnable
{

... removed many irrelevant methods

public void run()
{
    byte[] readBuffer = new byte[512 * 1024];
    while (isRunning)
    {
        //ioLogger.debug("in while(isRunning) loop");
        try
        {
            int length = input.available();
            if (length > 0)
            {
                int read = input.read(readBuffer, 0, readBuffer.length);

                if (read < 0)
                {
                    isRunning = false;
                    //@todo: do we disconnect?
                    ioLogger.debug("setting isRunning FALSE after read < 0");
                }
                else
                {
                   //read data and process
                }
            }
            else
            {
                //ioLogger.debug("nothing to read, sleeping");
                try
                {
                    Thread.sleep( 10 );
                }
                catch ( InterruptedException e )
                {
                    //do nothing, keep going
                }
            }
        }
    // some catch blocks and logging after this

この頻度で睡眠を呼び出すと問題が発生するのではないかと心配しているので、状況を緩和するために睡眠時間を10から250に増やしてみました。これで問題は多少改善されますが、時間の経過とともに同じ問題が発生します。ヒープスペースがなくなるまで、スレッドを着実にリークします。

誰かがこの行動について何か洞察を持っていますか?Thread.sleep()このような問題を引き起こすほど基本的なことはないと思います。

4

4 に答える 4

9

Thread.sleep()確かに問題ではありません。スレッドなどは作成されません。

私はそれisRunningが決して設定されておらず(または同期が不十分なために変更が表示されない)、古いスレッドがまだ実行されている間に新しいスレッドが作成されると推測することしかできません。

availableところで、スレッドを絶えず呼び出してスリープ状態にする代わりに、単にブロックすることができinput.read()ます。コードははるかに単純で応答性が高くなります。

于 2012-01-18T17:45:12.797 に答える
6

問題はThread.sleep()、ではなく、スレッドのロジックにあります。

投稿したコードから、スレッドは。のときに終了しisRunning = falseます。現在、にisRunning設定する唯一の方法falseinput.available()、正の値を返し、その後にinput.read()負の値を返す場合です。

それが事実であるとき、世界のいかなる状態も存在しないように思われます。

その結果、このrun()メソッドを使用するすべてのスレッドは、プロセスが存続する限り存続し、ほとんどの時間をに費やしThread.sleep()ます。

PSこれはあなたが投稿したコードに基づいています。現在表示していない設定に設定する方法がある場合、質問を更新してください。isRunningfalse

于 2012-01-18T18:00:02.960 に答える
2

Thread.sleep()何も「フォーク」せず、スレッドのリークについて検索するときに考慮に入れることはできません。

これらのスレッドを生成しているものを検索する必要があります。アプリケーションで新しいスレッドを作成するためのコードはどれですか?それはあなたが最初に答えなければならない質問です

于 2012-01-18T17:46:07.530 に答える
1

よくある間違いは、isRunningブール値を作成するのを忘れるvolatile ことです。このキーワードがないと、1つのスレッドで変更でき、別のスレッドがその変更を確認できる保証はありません。したがってisRunning、falseに設定している可能性がありますが、スレッドは引き続き実行されます。

この問題を修正するために、コードを劇的に単純化して、このような変数で回転するようにします。プライベート揮発性ブール値closed=false; プライベート最終InputStream入力。

public void close() throws IOException {
    closed = true;
    input.close();
}

public void run() {
  byte[] readBuffer = new byte[512 * 1024];
  try {
     // you wouldn't keep looping after an exception.
     int len;
     while ((len = input.read(readBuffer)) > 0) {
           //read data and process
     }
  } catch (IOException ioe) {
     if (!closed)
        // log unexpected exception
  }
}

簡単に作成すればするほど、機能する可能性が高くなります。;)

于 2012-01-18T20:25:09.570 に答える