Java では、コレクションが読み取り専用の場合、同期されていると宣言する必要がありますか? 質問する

Java では、コレクションが読み取り専用の場合、同期されていると宣言する必要がありますか? 質問する

J2EE Web アプリケーションが起動したときに、コレクションを 1 回だけ入力します。その後、複数のスレッドが同時にそのコレクションにアクセスする可能性がありますが、その目的は読み取りのみです。

同期コレクションの使用は parallels 書き込みに必須であることは知っていますが、 parallels 読み取りにも必要ですか?

ベストアンサー1

通常は、この場合、コレクションの内部状態は変更されないため、いいえです。コレクションを反復処理すると、反復子の新しいインスタンスが作成され、反復の状態は反復子のインスタンスごとに異なります。


余談:コレクションを読み取り専用にしておくと、コレクション自体の変更が防止されるだけであることに注意してください。コレクションの各要素は引き続き変更可能です。

class Test {
    public Test(final int a, final int b) {
        this.a = a;
        this.b = b;
    }

    public int a;
    public int b;
}

public class Main {

    public static void main(String[] args) throws Exception {
        List<Test> values = new ArrayList<Test>(2);
        values.add(new Test(1, 2));
        values.add(new Test(3, 4));

        List<Test> readOnly = Collections.unmodifiableList(values);
        for (Test t : readOnly) {
            t.a = 5;
        }

        for (Test t : values) {
            System.out.println(t.a);
        }
    }

}

出力は次のようになります:

5
5

@WMR の回答からの重要な考慮事項。

これは、コレクションを読み取っているスレッドがコレクションを埋める前か後に開始されたかによって異なります。コレクションを埋める前にスレッドが開始された場合、これらのスレッドが更新された値を表示するかどうかは (同期しない限り) 保証されません。

その理由は Java メモリ モデルにあります。詳しく知りたい場合は、次のリンクの「可視性」セクションをお読みください。http://gee.cs.oswego.edu/dl/cpj/jmm.html

また、コレクションを埋めた後にスレッドが開始された場合でも、コレクションの実装は読み取り操作でも内部状態を変更する可能性があるため、同期が必要になる場合があります(マイケル・バー・シナイ、そのようなコレクションが存在することを知りませんでした。

並行性に関するもう1つの非常に興味深い読み物として、オブジェクトの公開、可視性などのトピックをより詳細にカバーしているBrian Goetzの本があります。Java の並行処理の実践

おすすめ記事