3

ループ内でこれらのことを行う N 個のスレッドがあります。共有変数を増やし、共有変数の値が N かどうかを確認し (そうであれば、値をキューに入れます)、wait() を実行します。q 変数をチェックする脅威がもう 1 つあります。queue が true の場合、notifyAll() を実行します。その後、N 個のスレッドが起動し、別のループを実行する必要があります。しかし、いくつかのスレッドが予告なしに起きているようです。偽のウェイクアップについて読んだことがありますが、偽のウェイクアップであるかどうかを確認するために while() にどの条件を設定すればよいかわかりません。

以下は私のコードの例です(同じではありませんが、意味は非常に似ています):

共有クラスはすべてのスレッド間で共有されます:

class Shared {
    volatile int v = 0;
}

10 個のスレッドを作成して実行します。

class NThreads implements Runnable {
    private Shared shared;
    private QThread q;
    static int N = 0; /* N - number of threads */

    public NThreads(QThread q, Shared shared) {
        this.q = q;
        this.shared = shared;
        ++N;
    }

    @Override
    public void run() {
        for (int i=0;i<1048575;++i) {
            doSomeCalculations();
            loop();
        }
    }

    private void loop() {
        synchronized (shared) {
            if (++shared.v == N) {
                shared.v = 0;
                synchronized (Q) {
                    q.q = true;
                }
                shared.wait();
            } else {
                shared.wait();
            }
        }
    }
}

q の変更を待ってから notifyAll() を呼び出す QThread は 1 つだけです。

class QThread implements Runnable {
    private Shared shared;
    volatile boolean q = false;

    public QThread(Shared shared) {
        this.shared = shared;
    }

    @Override
    public void run() {
        for (;;) {
            if (q) {
                synchronized (this) {
                    q = false;
                }
                synchronized (shared) {
                    shared.notifyAll();
                }
            }
            doSomethingElse();
            // or even: Thread.yield();
        }
    }
}

すべてを実行するメイン クラス:

class Main {
    public static void main(String[] args) {
        Shared shared = new Shared();
        QThread qt = new QThread(shared);
        NThread[] nt = new NThread[10];
        for (int i=0; i<nt.length; ++i) {
            nt[i] = new NThread(qt, shared);
        }
        Thread[] threads = new Thread[nt.length+1];
        threads[0] = new Thread(qt);
        for (int i=0; i<nt.length; ++i) {
            threads[1+i] = new Thread(nt[i]);
        }

        for (int i=0; i<threads.length; ++i) {
            threads[i].start();
        }

        for (int i=0; i<threads.length; ++i) {
            threads[i].join();
        }
    }
}

ループを終了する (NThreads からの) スレッドがある場合もありますが、他のスレッドは終了しません。それは偽のウェイクアップが原因だと思います。偽のウェイクアップのケーキを取得し、すべてのスレッドが作業を継続できることを確認する条件を作成する方法は?

java.util.concurrent に便利なクラスがあるのではないでしょうか? しかし、私は面白いものを見ませんでした... :(

4

1 に答える 1

3

Object.wait()の JavaDocsでは、偽のウェイクアップの可能性について説明しています。また、待機ループを終了する前に、外部条件をチェックするループで wait() を使用する必要があることにも言及しています。

これを実現するには、 loop() メソッドを少し再構築する必要があります

private void loop() {
    synchronized (shared) {
        shared.v++;
        while(shared.v < N) {
            shared.wait();
        }

        shared.v = 0;
        synchronized (Q) {
            q.q = true;
        } 
    }

最終的には、これらのタイプのものを間違えやすいため、これが組み込まれている同時実行ライブラリをおそらく見つける必要があります。出発点として、Google の Guava、java.util.concurrency、または多くの Apache Commons ライブラリの 1 つを検討します。

于 2012-10-30T22:55:36.340 に答える