並行性の問題
Javaプログラムでは、すべてのスレッドがメインメモリを共有しますが、各スレッドは独自のワーキングメモリ(レジスタ、スタック、書き込みバッファ、キャッシュなどを含む仮想コンセプト)を持ち、ワーキングメモリはメインメモリと相互作用してデータを同期します、そしてスレッドは自分の作業メモリにしかアクセスできないため、マルチスレッド環境では、作業メモリデータに不整合が生じ、同時実行性の問題が発生しやすくなります。
また、複数のスレッド間でのスレッドの同期、つまり、スレッド間での通信と連携の方法にも問題があります。
スレッドセーフ
複数のスレッドがオブジェクトにアクセスする場合、ランタイム環境でこれらのスレッドのスケジューリングと代替実行を考慮する必要がない場合は、追加の同期や呼び出し元の他の調整された操作は必要ありません。このオブジェクトを呼び出す動作は次のとおりです。正しい結果が得られると、このオブジェクトはスレッドセーフになります。
再注文
プログラムを実行するときのパフォーマンスを向上させるために、コンパイラとプロセッサはしばしば命令を並べ替えます:
-
コンパイラー最適化再配列:シングルスレッドプログラムのセマンティクスを変更せずに、ステートメントの実行順序を再配置できます。
-
命令レベルの並列並べ替え:データに依存しない場合、プロセッサはステートメントに対応する機械語命令の実行順序を変更できます。
-
メモリの並べ替え:プロセッサはキャッシュと読み取り/書き込みバッファを使用するため、ロードとストアの操作が順不同で実行されているように見えることがあります。
これらの基本的な並べ替えレベルは、プログラムの正確性を保証するために、次の仕様に従います。
-
データの依存関係:たとえば、読み取りと書き込みの関係にある2つの操作の間にデータの依存関係がありますが、マルチスレッドの場合のデータの依存関係は考慮されません。
-
as-if-serialセマンティクス:並べ替えの方法に関係なく、シングルスレッドプログラムの実行結果は変更されません。
コンパイラーの再配列と再配列は、マルチスレッド化とマルチプロセッサーの状況を考慮しないため、並行環境で予期しない問題が発生します。
揮発性キーワード
可視性:このキーワードのセマンティクスにより、新しい値をメインメモリにすぐに同期し、使用する直前にメインメモリから更新することができます。
順序付け:メモリバリアを作成して(命令の並べ替えで後続の命令をメモリバリアの前の位置に並べ替えることはできません)、命令の並べ替えを禁止できます。
同時実行ツール
-
ロック:相互に排他的な同期。
-
同期:全能であるように見えますが、通常、全能のパフォーマンスにはパフォーマンスの問題が伴います。
-
Reentrantlock:より柔軟で、中断されるのを待つという特徴があり、公平なロックを実現でき、複数の条件をバインドできます。
-
待機は中断される可能性があります:ロックを保持しているスレッドが長時間ロックを解放しない場合、待機スレッドは待機をあきらめ、代わりに他のものを処理できます。
-
公平なロック:複数のスレッドが同じロックを待機している場合、それらは、ロックを申請する時系列に従って順番にロックを取得する必要があります。同期ロックは不公平です。つまり、ロックが解放されると、待機中のスレッドがロックを取得する機会があります。Reentrantlockもデフォルトでは不公平ですが、公平なロックとして構成できます。
-
複数の条件のバインド:ロックオブジェクトの同期、待機、通知、または通知すべてで、暗黙の条件を実装できます。複数の条件に関連付ける場合は、追加のロックを追加する必要があります。Reentrantlockは、newConditionメソッドを使用して複数の条件をバインドできます。
さらに、Reentrantlockは、onitionの待機とシグナルを通じてスレッド間で通信できます。
-
-
-
CAS:比較と交換、楽観的ロックに似たメカニズムで、更新されるたびに古い値が現在の値と比較され、同じ場合は更新が実行され、それ以外の場合は成功するまで再試行します。
-
ThreadLocal:ThreadLocalクラスはデータの分離を解決します。つまり、ThreadLocal内の複数のスレッド内のデータは互いに干渉せず、取り出されたときに自分のデータのみがフェッチされます。
-
不変オブジェクト。
-
Javaコンカレントパッケージのクラスであるスレッドセーフティを保証するCASに基づくAQS、Abstract Queued Synchronizerは、いくつかのテンプレートメソッドを提供します。
同期化された
-
volatileはスレッド同期の軽量実装であり、そのパフォーマンスは同期よりも優れています。JDK 6バージョンの最適化により、同期の効率が大幅に向上し、開発でより多く使用されます。
-
揮発性の変更された変数、同期された変更されたメソッド、コードブロック。
-
volatileへのマルチスレッドアクセスはブロックされませんが、同期はブロックされます。
-
揮発性はデータの可視性を保証できますが、アトミック性は保証できません。同期はアトミック性を保証できます。プライベートメモリとパブリックメモリのデータを同期するため、間接的に可視性を保証できます。
同時収集
並行コレクションとは、java.util.concurrentの下のコレクションクラスを指し、以下が一般的に使用されます。
-
ConcurrentHashMap:HashMapのスレッドセーフバージョン。コレクションの同期メソッドよりもパフォーマンスが高くなります。
-
CopyOnWriteArrayList:ArrayListのスレッドセーフバージョン、永続的なデータ構造。つまり、リストに書き込むときに、元のリストのコピーが操作に使用されます。
-
LinkedBlockngQueue:ブロッキングキューの実装。
シンクロナイザー
-
CountDownLatch:カウンターのような関数を実装できます。
-
CycliBarrier:ループバックバリア。これは、スレッドのグループが特定の状態を待機してから、それらを一度に実行できるようにします。
-
セマフォ:セマフォは、同時アクセススレッドの数を制御します。acquire()でパーミッションを取得し、release()でパーミッションを解放します。
並行性フレームワーク
-
執行者
-
フォーク/ジョイン
-
俳優
並行プログラミングの提案
-
スレッドに名前を付けると、デバッグに役立ちます。
-
不変クラスを使用すると、すべての属性とクラスが最終的に不変となり、スレッドの安全性を確保できます。
-
デッドロックを回避するために、常にグローバルな固定順序で複数のロックを取得してください。
-
同期範囲を最小化します。
-
セグメントロック。
-
同期ではなく揮発性を使用します。
-
-