0

いくつかのマルチスレッド Java コードで発行エラーを引き起こそうとしています。

以下のサンプルはうまくいくように見えますが、今のところ期待どおりに動作します。確かに、私はこれを MacBook Pro (2.8 GHz Intel Core i7 を搭載した OSX 10.7.4) で 2 つのコア (およびハイパースレッディング) のみで実行しています。したがって、一度に実行できるスレッドは 4 つだけです。

出版の失敗を誘発するためのより良いアイデアはありますか?

package demo;

import java.util.concurrent.CyclicBarrier;

public class UnsafePublicationTest {
private static final String FIRST_VAL = "FAIL";
private static final String SECOND_VAL = "GOOD";

public void test() throws Exception {
    UnsafePublisher unsafe = new UnsafePublisher();
    unsafe.setValue(FIRST_VAL);
    CyclicBarrier gate = launchThreads(10, unsafe);
    gate.await();  // Start all threads at once
    gate.await();  // Each thread reads the first value

    // Should cause errors since update is not published
    unsafe.setValue(SECOND_VAL);
    gate.await();  // Each thread tries for the second value
    gate.await();  // Wait for the readers finish
}

private CyclicBarrier launchThreads(int count, UnsafePublisher unsafe) {
    CyclicBarrier gate = new CyclicBarrier(count + 1);
    for (int id = 0; id < count; id++) {
        ValueReader rdr = new ValueReader(id, gate, unsafe);
        rdr.start();
    }
    return gate;
}

private static class UnsafePublisher {
    private String fValue;

    public UnsafePublisher() { /* no synthetic ctor */ }

    public void setValue(String value) {
        this.fValue = value;
    }

    public String getValue() {
        return fValue;
    }
}

private static class ValueReader extends Thread {
    private final int fId;
    private final CyclicBarrier fGate;
    private final UnsafePublisher fTest;

    public ValueReader(int id, CyclicBarrier gate, UnsafePublisher test) {
        fId = id;
        fGate = gate;
        fTest = test;
    }

    public void run() {
        try {
            fGate.await();
            int noOp = this.hashCode();
            // Try to get the thread to cache the value.
            for (int i = 0; i < 10000; i ++) {
                for (int j = 0; j < 10000; j++) {
                    String first = fTest.getValue();
                    noOp = noOp ^ first.hashCode();
                    if (!FIRST_VAL.equals(first))
                        System.out.println("Thread " + fId + " read " + first);
                }
            }
            fGate.await();

            // Between these awaits, the value is changed.

            fGate.await();
            String second = fTest.getValue();
            if (!SECOND_VAL.equals(second))
                System.out.println("Thread " + fId + " read " + second);
            System.out.println("Thread " + fId + " hash " + noOp);
            fGate.await();

        } catch (Exception err) { /* ignore */ }
    }
}

public static void main(String[] args) throws Exception {
    UnsafePublicationTest test = new UnsafePublicationTest();
    test.test();
}

}

4

1 に答える 1

0

これをデバッグするのは難しいです:)私はまだあなたが達成したいことを理解しようとしていますが、私にとって、あなたが見ているものは正常であり、期待されています(あなたがそれを掘り下げてコードを理解する場合)。これが何が起こるかです:

  • CyclicBarrierは11に設定されています。

    メインスレッドが他の10個のスレッドを開始し、それらすべてがrunメソッドの実行を開始するとします。しかし、彼らはすぐにブロックします。ここでは、メインスレッドとこれらの10個のスレッドが起動する順序は重要ではありません。また、メインスレッドではgate.await()を2回呼び出して、各スレッドがforループを実行できるようにするため、重要ではありません。forループが完了したら、gate.await()を2回呼び出します。 、したがって、バリアを再び持ち上げます。

    • 今、私を最も混乱させる部分が来ます。runメソッドでgate.await()を3回呼び出すと、前のステップでバリアが「解除」されたため、すべてがブロックされますここでも順序は重要ではありません。最初にメインスレッドが呼び出され、「fValue」の値が「GOOD」に設定されてから、10個のスレッドがバリアを待機していると言えます。これは重要ではありません。importnatとは、このステートメントが次のことを示しているという事実です。

コード(sample1と呼びましょう):

String second = test.getValue();
if (!SECOND_VAL.equals(second)){
     System.out.println("Thread " + i + " read " + second); 
}

これはrunメソッド内にあり、mainでこの呼び出しを行った後にのみ100%実行されます。

 unsafe.setValue(SECOND_VAL); // call it sample2

問題はここのどこかにあると思います(悪魔は常に詳細にあります:))。

そして、sample2がsample1の前に100%実行されることに同意する場合、このコードのオッズは何ですか?

 if (!SECOND_VAL.equals(second)){
      System.out.println("Thread " + i + " read " + second);
 }

まあ、私には、なし。

したがって、私の質問、あなたは何を証明しようとしていますか?より良い/より単純な例を考えることができるでしょうか?それでもこれに固執したい場合は、おそらく達成しようとしていることをもっと説明する必要があります。

于 2012-08-23T07:34:24.610 に答える