Javaの同時実行性に問題があります。はい、ほぼ同じタイトルの質問を見ましたが、それらはすべて微妙に異なることを質問しているようでした。はい、JavaConcurrencyinPracticeを読みました。はい、それがトピックの事実上の参照である理由がわかります。はい、スレッドセーフクラスでのフィールドの公開に関するセクションを特に読みました。はい、誰かが私にその本を単に指し示すことを知っているという事実に関係なく、私はまだJavaで並行性の質問をするつもりです。
しかし、これは私を困惑させました-揮発性および/または同期アクセスを備えた正しい読み取り/書き込み順序を保証することにより、スレッドセーフな方法で可変プリミティブフィールドを簡単に公開できること、および64ビットプリミティブにはアトミックアクセスが必要であることを知っています読み取り/書き込み操作の原子性が不足しているためです。クラスのフィールドの特定の「スナップショット」で実行する必要があるコードのチャンクにロックを使用することについて知っています。AtomicLong<>などの機能を備えたアトミックパッケージを十分に認識しています。
しかし、スレッドセーフでないオブジェクトをスレッドセーフクラスのフィールドとして公開することに関しては、まだ混乱しています。
私が見ることができることから、ゲッターでそれへの参照を返すとすぐに、あなたはいつでも使用できる呼び出し元にオブジェクトのコンテンツへの前例のないアクセスを与えました。また、セッターを指定すると、セッターを使用しているオブジェクトの外部で制御できる可能性のあるオブジェクトへのオブジェクト参照を設定できるようになります。
とにかく、スレッドセーフでないオブジェクトからスレッドセーフなクラスを作成するには、それらをすべてプライベート/保護し、すべてのメソッドのクラスにスレッドセーフなラッパーメソッドを作成して、すべての非スレッドセーフなオブジェクトを作成する必要があります。クラスのユーザーが使用したいと思うかもしれないことを持っている。そして、これは定型的な悪夢のように聞こえます。
つまり、ゲッターのオブジェクトにAtomicReference <>を返すと、.get()を使用して、同期されていないアクセスを再度取得できます。
私が考えたもう1つの方法は、すべてのゲッターが古いオブジェクトに基づいてスレッドセーフでないオブジェクトの新しいコピーを返すようにすることでした。つまり、セッターにも同じことが適用され、変更は無関係になります。しかし、Javaには、オブジェクトのクローンを作成するための絶望的に複雑なシステム(浅いコピー、深いコピー、特定のコピーなど)があります。また、これは非常に非効率的であるため、Clojureのような不変性用に設計された言語を使用するよりも速くはありません。実際、そのような言語では、複数の不変データが舞台裏で同じデータを共有できることを考えると、おそらくはるかに遅くなります。
では、公開された非スレッドセーフオブジェクトのスレッドセーフクラスを実行可能な方法で作成するにはどうすればよいですか?
前もって感謝します。