I.はじめに
開発プロセスのマルチスレッドでは、あなたは、このような場面に遭遇することがあります。同時に複数のスレッドが変数を操作するとき、スレッド間のタイムラグがあるだろう、との時間差で、共有データの値は、私たちが持っているので、変更された可能性がありますマルチスレッド環境で、データ値を読み込むために、各スレッドが最新の状態にしていること?確実にする方法 見つけるためにスレッド同期メカニズム〜
第二に、スレッドの同期「ロック」
現在のスレッド、他のスレッドが使用できない場合、フロントはマルチスレッドのシナリオを理解するために、データを読む必要があり、スレッドごとに値を確保する必要が最新の状態である、そして我々は、現在と同等の「ロック」、このデータの動作を保証するが必要スレッド「ロック」、この時点で我々が学ばなければならないこれを実現する方法の次のシナリオをライブデータへのアクセスを読み取りおよび書き込み。
まずは、いくつかの大きな成果物だけでなく、その一般的な効果を理解してみましょう:
- 同期:キーワードは、この方法は、修正されてもよい、コードブロックを修正することができます
- 揮発性:特別可変ドメイン
- ReentrantLockの:リエントラントロック
- アトミック :アトミック変数
第三に、スレッド同期のコメント
同期同期方法
定義:キーワード修飾法があり、同期。
- 各Javaオブジェクトを持っている内蔵のロック、synchronizedキーワード修飾法の使用は、内蔵のロックする「ロック」の全体的なアプローチを。
- 各スレッドは、このメソッドを呼び出す前に、あなたは内蔵のロック、それ以外の場合はブロックされている取得する必要があります。
- PS: synchronizedキーワードに変更使用している場合は、静的メソッドをこの時点では、静的メソッドの呼び出しがするかどうするクラス全体をロック
/ ** *同期同期方法 * / パブリック クラスMySynchronizedMethod { プライベート 静的の int型のカウント= 0 ; パブリック 静的 ボイドメイン(最終文字列[]引数)がスローInterruptedExceptionあるが{ //はTestThreadオブジェクトを作成 TestThread threadRunable = 新しい新しいTestThreadは(); // 増加スレッド10スレッドオブジェクトの スレッドスレッド1 = 新しい新しいスレッド(threadRunable)。 スレッド2スレッド = 新しいスレッド(threadRunableを)。 thread3スレッド = 新しいスレッド(threadRunableを)。 thread4スレッド = 新しいスレッド(threadRunableを)。 thread5スレッド = 新しいスレッド(threadRunableを)。 thread6スレッド = 新しいスレッド(threadRunableを)。 thread7スレッド = 新しいスレッド(threadRunableを)。 thread8スレッド = 新しいスレッド(threadRunableを)。 thread9スレッド = 新しいスレッド(threadRunableを)。 スレッドThread10 = 新しい新しいスレッド(threadRunable); // 10件のスレッドが同時に開始 thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread6.start(); thread7.start(); thread8.start(); thread9.start(); thread10.start(); } / ** *同期方法 * / パブリック 静的 同期 ボイドcountNum(){ ため(INT iが= 0; I <100000; I ++ ){ カウント ++ ; System.out.println(カウント)。 } } / ** *スレッドのエンティティ(Runnableを実装します) * / 静的 クラス TestThread 実装Runnableを{ 公共 ボイドRUN(){ //は同期メソッド呼び出し countNumを(); } } }
シンクブロックは、同期
同期方法と同様に、同期は通常、方法全体を同期させるために必要な高いオーバーヘッド操作されないで、シンクブロック同期方法は、より好ましくは比較的少数です。
上記のコードと同様に、唯一の同じ場所を掲示していません。
/ ** *同期方法 * / 公共の 静的な 無効countNum(){ のために(int型 I = 0; I <100000; I ++ ){ // PS:これは、時間がステートメントブロックを同期させるための静的メソッドであるので、それは全体のクラス(の同期が組み込まれてロックする必要があります内蔵ロックエンティティの代表的なパラメータ)を取得する 同期(MySynchronizedMethod。クラス){ カウント ++ ; } System.out.println(カウント)。 } }
特殊フィールド変数(揮発性)
- volatileキーワードは、アクセスするための可変ドメインを提供無料のロック機構を
- ドメインに仮想マシンを伝えるために同等の揮発性の修正ドメインをされて使用し、他のスレッドによって更新されてもよいです
- 従ってフィールドの再計算、各使用ではなく、使用したレジスタ値を
- 揮発性アトミック操作を提供していない、変数の最終的な種類を変更するために使用することができません
// volatileキーワード使用して変数を変更する
プライベート 静的 揮発性の int型の COUNT = 0;
PS:揮発性のみアトミック操作(例えば、N = M + 1)が、有効である場合に関する動作そのものの値であれば(例えば:N ++; N = N +としません作業、慣れていませんこのキーワードと同期することは推奨されません。
ReenreantLockリエントラントロック
一般的な方法のReenreantLockクラスは以下のとおりです。
- ReentrantLockの() :ReentrantLockのインスタンスを作成します。
- ロック() :ロックを取得
- UNLOCK() :ロックを解除
// リエントラントロック宣言 プライベート 静的ロックロック= 新新)ReentrantLockのを(; / ** *同期方法 * / パブリック 静的 ボイドcountNum(){ 用(INT iが= 0; I <100000; I ++ ){ Lock.lock(); // ロックを開始 ++ COUNTを。 System.out.println(カウント)。 lock.unlock(); // ロック解除 } }
アトミックアトミック変数
++カウントに類似した上記の例からわかるように、法、原子操作は実際にはありませんが、後に読み取り、書き込み、変更の3つの手順を。
原則:CASの原則(比較交換)、各スレッドが持つ前に、動作になります古い期待とメモリの値が比較され、同時にメモリ値、新しい値にスレッドがこれを行う際に、他のスレッド失敗し、再度試すことができ、または何もしない、そしてスレッドが中断されることはありません。
問題: ABAの問題の解説参照ここ-
/ ** 同期同期ロックを達成するために、*アトミックアトミック変数 * / パブリック クラス{MyAtomic // 複数のスレッドは、(代わりのAtomicInteger同期ロックを使用する)変数を共有 プライベート 静的のAtomicIntegerカウント= 新しい新規のAtomicInteger(0 )。 // 共有変数の値を取得する パブリック 静的整数同様にgetCount(){ 戻りcount.getを(); } // インクリメント方法 パブリック 静的 ボイド増加(){ count.incrementAndGet(); } パブリック 静的 ボイドメイン(最終文字列[]引数)はスローInterruptedExceptionある{ // スレッドプールのスレッドを作成し50 ExecutorServiceの= Executors.newFixedThreadPoolキュータ(50 ); // PUTスレッドオブジェクト50を実行 するための(INT I = 0。 I <50; I ++ ){ executor.submit(新しいTestThread()); } } / ** *同期方法 * / パブリック 静的 ボイドcountNum(){ 用(INT iが= 0; I <10000; I ++ ){ 増加する(); System.out.println(同様にgetCount())。 } } / ** *スレッドのエンティティ(Runnableを実装します) * / 静的 クラス TestThread 実装Runnableを{ 公共 ボイドRUN(){ //は同期メソッド呼び出し countNumを(); } } }
結果: