8

Javaの同時実行性に問題があります。はい、ほぼ同じタイトルの質問を見ましたが、それらはすべて微妙に異なることを質問しているようでした。はい、JavaConcurrencyinPracticeを読みまし。はい、それがトピックの事実上の参照である理由がわかります。はい、スレッドセーフクラスでのフィールドの公開に関するセクションを特に読みました。はい、誰かが私にその本を単に指し示すことを知っているという事実に関係なく、私はまだJavaで並行性の質問をするつもりです。

しかし、これは私を困惑させました-揮発性および/または同期アクセスを備えた正しい読み取り/書き込み順序を保証することにより、スレッドセーフな方法で可変プリミティブフィールドを簡単に公開できること、および64ビットプリミティブにはアトミックアクセスが必要であることを知っています読み取り/書き込み操作の原子性が不足しているためです。クラスのフィールドの特定の「スナップショット」で実行する必要があるコードのチャンクにロックを使用することについて知っています。AtomicLong<>などの機能を備えたアトミックパッケージを十分に認識しています。

しかし、スレッドセーフでないオブジェクトをスレッドセーフクラスのフィールドとして公開することに関しては、まだ混乱しています。

私が見ることができることから、ゲッターでそれへの参照を返すとすぐに、あなたはいつでも使用できる呼び出し元にオブジェクトのコンテンツへの前例のないアクセスを与えました。また、セッターを指定すると、セッターを使用しているオブジェクトの外部で制御できる可能性のあるオブジェクトへのオブジェクト参照を設定できるようになります。

とにかく、スレッドセーフでないオブジェクトからスレッドセーフなクラスを作成するには、それらをすべてプライベート/保護し、すべてのメソッドのクラスにスレッドセーフなラッパーメソッドを作成して、すべての非スレッドセーフなオブジェクトを作成する必要があります。クラスのユーザーが使用したいと思うかもしれないことを持っている。そして、これは定型的な悪夢のように聞こえます。

つまり、ゲッターのオブジェクトにAtomicReference <>を返すと、.get()を使用して、同期されていないアクセスを再度取得できます。

私が考えたもう1つの方法は、すべてのゲッターが古いオブジェクトに基づいてスレッドセーフでないオブジェクトの新しいコピーを返すようにすることでした。つまり、セッターにも同じことが適用され、変更は無関係になります。しかし、Javaには、オブジェクトのクローンを作成するための絶望的に複雑なシステム(浅いコピー、深いコピー、特定のコピーなど)があります。また、これは非常に非効率的であるため、Clojureのような不変性用に設計された言語を使用するよりも速くはありません。実際、そのような言語では、複数の不変データが舞台裏で同じデータを共有できることを考えると、おそらくはるかに遅くなります。

では、公開された非スレッドセーフオブジェクトのスレッドセーフクラスを実行可能な方法で作成するにはどうすればよいですか?

前もって感謝します。

4

1 に答える 1

4

安全でないオブジェクトへの参照が周囲のスレッドにエスケープされている場合、他のスレッドを停止して状態を変更することはできないため、参照を安全に保つ必要があります。複雑なオブジェクトを返す必要がある場合は、データをプライベートにし、アクセスと変更をカプセル化するメソッドを投入し、スレッドセーフなコピーを作成します(はい、クローン作成は面倒です)。

http://en.wikipedia.org/wiki/Law_of_Demeterの設計原則を見てみてください。引用:特に、オブジェクトは、別のメソッドによって返されるメンバーオブジェクトのメソッドを呼び出さないようにする必要があります。フィールド識別子としてドットを使用する多くの最新のオブジェクト指向言語では、法則は単に「1つのドットのみを使用する」と表現できます。つまり、コードabMethod()は、a.Method()が違反しない法則に違反します。簡単な例として、犬を散歩させたい場合、犬の足に直接歩くように命令するのは愚かです。代わりに、犬に命令して、犬に自分の足の世話をさせます。

ps:それは自由形式の質問だと思います。

于 2011-07-17T12:33:20.197 に答える