同時にアクセスされるフィールドがあり、何度も読み取られ、めったに書き込まれないと仮定します。
public Object myRef = new Object();
スレッドT1がmyRefを1分に1回別の値に設定し、他のN個のスレッドがmyRefを数十億回連続して同時に読み取るとします。myRefが最終的にすべてのスレッドに表示されることだけが必要です。
簡単な解決策は、AtomicReferenceまたは単にvolatileを次のように使用することです。
public volatile Object myRef = new Object();
ただし、afaikの揮発性読み取りではパフォーマンスコストが発生します。非常に小さいことはわかっていますが、これは実際に必要なものというよりは、私が不思議に思っているようなものです。したがって、パフォーマンスに関係なく、これは純粋に理論的な質問であると想定しましょう。
つまり、質問は次のようになります。書き込みサイトで何かを行うことによって、書き込みがほとんどない参照の揮発性読み取りを安全にバイパスする方法はありますか?
いくつか読んだ後、メモリの壁が私が必要とするものであるように見える。したがって、このような構成が存在する場合、私の問題は解決されます。
- 書く
- バリアを呼び出す(同期)
- すべてが同期され、すべてのスレッドに新しい値が表示されます。(読み取りサイトでの永続的なコストがないと、キャッシュが同期されるため、古くなったり、一時的なコストが発生する可能性がありますが、その後は通常のフィールドに戻り、次の書き込みまで続きます)。
そのような構造はJava、または一般にありますか?この時点で私は仕方がありませんが、このようなものが存在する場合、それを維持するはるかに賢い人々によってすでにアトミックパッケージに組み込まれていると思います。(不定期に頻繁に読み取りと書き込みを行う必要はなかったのではないでしょうか?)それで、私の考えに何か問題があり、そのような構成はまったく不可能ですか?
いくつかのコードサンプルが同様の目的で「揮発性」を使用し、それが契約前に発生することを利用するのを見てきました。別の同期フィールドがあります。例:
public Object myRef = new Object();
public volatile int sync = 0;
そしてスレッド/サイトを書く時:
myRef = new Object();
sync += 1 //volatile write to emulate barrier
これが機能するかどうかはわかりませんが、x86アーキテクチャでのみ機能すると主張する人もいます。JMSの関連セクションを読んだ後、その揮発性書き込みがmyRefの新しい値を確認する必要があるスレッドからの揮発性読み取りと結合されている場合にのみ、動作することが保証されていると思います。(したがって、揮発性の読み取りを取り除きません)。
元の質問に戻ります。これはまったく可能ですか?Javaで可能ですか?Java 9 VarHandlesの新しいAPIの1つで可能ですか?
sync += 1;
読み取り、読み取りスレッドがsync
値を読み取った場合、myRef
更新も表示すると述べています。最終的にはリーダーが更新を確認するだけでよいので、これを利用して、リーダースレッドの1000回の反復ごとにのみ同期を読み取るなどの利点があります。しかし、同様のトリックをvolatile
で行うこともできます。myRef
フィールドをリーダーで1000回反復してキャッシュし、揮発性を使用して再度読み取ります...
sync
読者がフィールドを意味する場合、いいえ、sync
毎回の反復でフィールドに触れることはありません。更新があるかどうかを確認したい場合は、日和見的に行います。それは簡単な解決策をキャッシュするようになり、言ったmyRef
...それを再読み込み、その後、1000回のラウンドのために