リンクされたノードで構成されるデータ構造があります。これは単純な LinkedList と考えることができます。リストの各ノードは、何らかの値と、他のノードを指す次のフィールド、または最後のノードの場合は null で構成されます。最初のノードはルートとして機能し、値はなく、次のノードを指すだけです。他のすべてのノードは実質的に不変であり、特定の状況に関連して構造体が破棄されない限り、一度作成されると値も次のフィールドも存続期間中に変更されません。
1 つ (1 つだけ) のスレッドが新しいノードをリストの先頭に追加します。これは、新しいオブジェクトを構築し、そのフィールドを設定し、次のフィールドをルートが指すオブジェクトに設定し、ルートの次のフィールドをこの新しいノードに設定することによって実現されます。
他のノードは、読み取りのみを実行して構造をブラウズします。ルート ノードへの参照があり、探しているものが見つかるか、リストの最後に到達するまで、他のノードを通過します。
私の質問は、次のフィールドを揮発性にするだけで十分ですか? 私の Java メモリ モデルの理解から、新しいノードを追加するときにメイン スレッド (新しいノードを追加するスレッド) が揮発性書き込みを実行する場合、すべてが正常に同期され、不整合は発生しません。
また、x86 アーキテクチャで揮発性変数の読み取りがパフォーマンスの低下を引き起こさないと仮定するのは正しいですか? 他のスレッドは次のフィールドを読み取る構造体を頻繁にブラウズするため、これがメモリバリアなどなしに自由に実行できることが重要です。
また、もうひとつ気になることがあります。構造をブラウズするスレッドは、いくつかの追加ノードも保持します。これらのノードは完全にスレッド ローカルであり、ノードを作成したスレッドのみが使用し、まったく共有されません。これらの追加ノードでは、次のフィールドが揮発性である必要はありません。さらに、volatile next フィールドを設定すると、望ましくないパフォーマンスの低下を引き起こすメモリ バリアが発生します。これを回避する方法はあるのだろうか。理想的には、次のフィールドが揮発性フィールドとして機能する場合と、通常のフィールドとして機能する場合があります;) または、完全に制御でき、必要なときにいつでも自分でメモリバリアを発行できれば完璧です。
編集:
また、これらすべての書き込みを別の揮発性変数に何らかの方法で同期することは可能でしょうか? たとえば、他の完全に無関係な静的変数はありますか? 揮発性書き込みは保留中のすべての書き込みをフラッシュするため、更新スレッドがすべての作業を行った後に、次のフィールドが揮発性ではなく、代わりに別の揮発性変数が書き込まれる可能性はありませんか?
リレーションの前に発生することはなく、以前の書き込みが並べ替えられる可能性があるため、私にはあまり安全ではないようです。次のフィールドの割り当ては、値フィールドの割り当てで再順序付けされる可能性があり、反復スレッドが一貫性のないオブジェクトの状態を観察することにつながります。
しかし、そのような安全なスキームを考え出すことは可能でしょうか? これはどう:
更新スレッドは、最初に新しいオブジェクトを構築し、その値フィールドを初期化し、その次のフィールドをルート ノードが指すノードに設定し、いくつかの静的変数で揮発性書き込みを実行し、ルート ノードの次のフィールドを新しく作成されたノードに設定します。