0

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

ありがとうございました。

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;
}
}
}
4

2 に答える 2

3

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

おそらく、QB#start()メソッドの最後で、QB#waitUntilFinished()すべてのスレッドが終了するのを待つことになっていますが、メソッドがインスタンスのロックを解放するのをまだ待っているため、メソッドにt入ることができません。QB#loadQB#start()QB

だから、循環デッドロック。

于 2012-04-11T22:32:08.943 に答える
1

編集:

さて、スレッドがバグからどのように削除されるかtListが完全に明らかになったことがわかりました。

インデックス 0 のスレッドが最初に終了すると、それ自体がリストから削除されます。つまり、インデックス 1 スレッドが終了すると、1 番目の位置が から削除されますが、それVectorはそれ自体を指していません。#2スレッドを削除しています。遅かれ早かれ、無効なインデックスを削除するため、削除が発生すると例外が発生します。

Vector位置ではなく、アドレスからアイテムを削除する必要があります。

 tList.remove(this);

これにより、現在のスレッドがリストから削除されます。また、開始ループで an のadd(t)代わりに anを実行する必要があります。add(i t)

 tList.add(t);

スレッドに渡される id 位置はまったく必要ありません。


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

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

しかし、リストからスレッドを削除するものは何も表示されません。たぶん、スレッドがそれぞれ終了すると、それらは自分自身を削除することになっていますか?

スレッドがそのループから抜け出せない場合tMonitor、次の呼び出しはありません。

waitingLock.notifyAll();

そのため、メイン スレッドは永久にハングしますwaitUntilFinished();

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

また、ブロック内にいるため、 sleepinを実行したくありません。次のことを行う必要があります。tMonitor()synchronized

  waitingLock.wait(10000);

何も通知することはありませんが、スリープ中にそのようにロックを保持するのは悪い形です。

于 2012-04-11T22:15:09.210 に答える