0

私は本「実際のJava並行性」を読んでいて、数ページ後にいくつかの疑問が生じました。

1) 非プリミティブなデータ型を持つ voltile : private volatile Student s; 非プリミティブデータ型が付属する場合、揮発性の重要性は何ですか? (この場合、すべてのスレッドに確実に表示されるのは、Strudent オブジェクトが現在指しているものであり、1 つのスレッド A が学生の内部メンバーを変更し、他のスレッドには表示されない可能性があると考えているだけだと思います。私は正しいですか? ??)

2) 内部メンバーが final として宣言されていなくても、変数は不変にできますか?? 例えば ​​:

Class  A {

    private Set<String> s = new Set();
    public A() {
        s.add("Moe");
        s.add("Larry");
        s.add("Curly");
    }
} 

このクラスでは Set を final にして不変にする必要がありますか、それともこのクラスはまだ不変ですか? (この場合でも、作成後にオブジェクトの状態を変更できないため)。

3)本には、揮発性クラスと不変クラスを組み合わせて使用​​ して同期を取得する方法を示す1つの例があります。その質問をする前に、もう 1 つ疑問があります。次のような関数があるとします。

private Student s = new Student;

void func() {
    s.func2();      // 1
    if(s.isPossible()) { //2
        s = new Student(); //3      
    }
}

a)func2() s の内部メンバーにアクセスします。ここで、スレッド A が 1 行目を実行した後に func2 に入り、スレッド B が新しいオブジェクトで s を同時に再割り当てするとします。スレッド A が再開すると、新しいオブジェクトまたは古いオブジェクトを使用しますか? ( s が最初にメモリ位置 100 (古いオブジェクト) を指し、新しいオブジェクトが割り当てられた後、200 (新しいオブジェクト) を指し始め、スレッド A が再開すると、アドレス 100 またはアドレス 200 にアクセスするとします)。

b) s を volatile にすると、上記のケースに違いはありますか。

4.) そしてこれが最後のものです

@Immutable
class OneValueCache {
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;
    public OneValueCache(BigInteger i,
    BigInteger[] factors) {
        lastNumber = i;
        lastFactors = Arrays.copyOf(factors, factors.length);
    }
    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i))
            return null;
        else
            return Arrays.copyOf(lastFactors, lastFactors.length);
    }
}

@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
    private volatile OneValueCache cache = new OneValueCache(null, null);
    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = cache.getFactors(i); // Position A

        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, factors); // Position B
        }
        encodeIntoResponse(resp, factors);
    }
}

book クラス "VolatileCachedFactorizer" への準拠はスレッドセーフです。スレッドセーフである理由は次のとおりです (間違っている場合は訂正してください)。Positin A と Position B は疑わしい位置です。

位置 A : キャッシュが不変オブジェクトを指しているため、関数呼び出しは安全です (そうですか?)。

ポジション B : 2 つの問題が発生する可能性があります

a) スレッドは、キャッシュが不適切に初期化されていることを確認します。不変オブジェクトは適切に初期化されることが保証されているため、この場合は不可能です (そうですか?)。

b) 他のスレッドからは見えない、新しく割り当てられたオブジェクト。キャッシュは揮発性であるため、このケースは不可能です (そうですか?)。

しかし、スレッド A が getFactors() を呼び出し、他のスレッド B が cache を再割り当てする可能性があります。この場合、A は引き続き古いオブジェクトを参照します (そうですか?)

4

2 に答える 2

2
  1. はい; volatile適用先の参照にのみ適用されます。

  2. いいえ; final フィールドによってたまたま指されているオブジェクトは、魔法のように不変になることはありません。
    変更可能な非公開メンバーを持つオブジェクトは、それらのメンバーが決して変更できない場合にのみ不変です。(明らかに)

于 2013-06-11T21:26:47.050 に答える
0

私のすべての答えをいくつかテストした後、わかりました。

  1. volatile は参照にのみ適用されます。volatile オブジェクトによる任意のオブジェクト ポイントは、他のスレッドから見える必要はありません。

  2. はい、最後は重要です。それがなければ、クラスのオブジェクトは不変ではありません。

  3. 変数 "obj" が位置 x (実際のオブジェクトが置かれている場所) を指しているとします。これは、obj の関数呼び出しが開始されたときに、関数呼び出し中に、他のスレッドが別のオブジェクトを割り当てた場合でも、すべてのメンバー変数が位置 x から読み取られます。 「オブジェクト」。

  4. すべての答えの仮定された説明は正しいです。

于 2013-06-13T20:31:17.863 に答える