複数のスレッド間の同期を達成するためにどのように?

まず、なぜスレッド安全性の問題がありますか?

複数のスレッドがグローバル変数や静的変数を共有する場合スレッド安全性の問題は、一般に、データの競合が発生する可能性があり、つまり、スレッドの安全性の問題、データの衝突が読み出し動作で発生していない場合、操作を書くのですか、より多くのスレッド環境を発生します簡単な問題チケットケースの例を見てみましょう:100のチケットのニーズがあり、2つのウィンドウがあり、同時にチケットをつかむ、マルチスレッド・シミュレーション・グラブ票エフェクトを使用してください。コード:パブリッククラスThreadTrain1はRunnableを{プライベートint型のカウント= 100を実装します。

@Override
public void run() {
	while (count > 0) {
		try {
			Thread.sleep(50);
		} catch (Exception e) {
			// TODO: handle exception
		}
		sale();
	}
}

public void sale() {

		System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "票");
		count--;
	 }
}
复制代码

}

パブリッククラスThreadDemo {パブリック静的無効メイン(文字列[] args){ThreadTrain1 threadTrain1 =新しいThreadTrain1()。スレッドT1 =新しいスレッド(threadTrain1、 "①号窗口"); スレッドT2 =新しいスレッド(threadTrain1、 "②号窗口"); t1.start(); t2.start(); }}运行结果

一つ我々は、ウィンドウを見つけることができますし、ウィンドウIIは、マルチスレッド環境でのリソースによって引き起こされたスレッドの安全性の問題を共有している、重複や売られ過ぎを販売します

第二に、どのようにスレッドの安全性の問題を解決するために

シンクロナイズド(/「sɪŋkrənaɪzd/)------同等の自動ロック(/lɒk/)--- JDK1.5契約とその彼女------同等マニュアルトランスミッション

  1. スレッド安全性の問題との間にマルチスレッドを解決する方法?A:使用同期は、複数のスレッドやロック(ロック)の間で同期。
  2. なぜスレッド同期またはスレッドの安全ロックは、この問題を解決することができるでしょうか?:可能なデータの矛盾(スレッドセーフの問題は)現在のスレッドの実行のみを許可し、起こります。後の実行のために他のスレッドをさせように、ロックを解除するためのコードの実行が完了した後。このケースでは、不安スレッドの問題を解決することができます。
  3. 複数のスレッド間の同期とは何ですか?A:複数のスレッドが他のスレッドからの干渉なしに、同じリソースを共有する場合。
  4. 何が足かせを検討する必要がありますか?:本当のグローバル変数の共有と同じ時間を作ります。
  5. ロックが解除された場合?A:プログラムコードが完了するか、例外がスローされ、ロックが解放されます

第三に、同期

3.1同期ブロックとは何ですか?:コードまで含めて、発生する可能性があり安全性の問題を通すことです。同期ブロックを発生することが同期(同一データ){スレッド}競合が(オブジェクト)同期され、ロックを保持しているスレッドは同期することができ、{//このオブジェクトは、任意のオブジェクトは、オブジェクトロックコードとして同期させる必要があることができます}でも、CPUの実装を取得するだけでなく、同期を前提に取得していないロックを保持している実行スレッド:

  1. 二つ以上のスレッドが存在する必要があります
  2. 、複数のスレッドがロックを決定するために必要な資源のより消費、ロックリソースをつかむ:マルチスレッドを欠点のセキュリティ問題を解決:利益を実行するには、その唯一のスレッド同期を確認する必要があります同じロックを使用して複数のスレッドでなければなりません。原理:スレッドがあり、すでにロックを持って、他のスレッドがCPUの執行力を持って、他のスレッドのリリースでロックを待っています。コードサンプル:プライベート静的オブジェクトOJ =新しいオブジェクト();公共ボイド販売(){//マルチスレッドを使用するための前提条件で、複数のスレッドがロックを取得することができます。//唯一のスレッドの実行を同期(OJ){IF(カウント> 0){System.out.printlnは(にThread.currentThread()短所効率のgetName()+ "の販売" +(100を低減することを可能にすることを保証 - + 1)+ "チケット")を数える; count--;}}} 4、同期機能4.1同期機能とは何ですか?:機能コードが方法における同期同期のサンプルと呼ばれる修正:{場合)パブリック同期ボイド販売((trainCount> 0){{のThread.sleep(40)を試みる;}キャッチ(例外e){}のSystem.out。 println(にThread.currentThread()のgetName()+ "の販売" +(100 - trainCount + 1)+。 "チケット。");}}学生が考えて、trainCount--を?どのようなロックとの同期機能?A:同期機能は、このロックを使用しています。証拠方法:スレッド同期コードブロックを使用して(これはロックアウト)、同期機能を使用するための別のスレッド。票をつかむための2つのスレッドが同期できない場合は、データエラー。コード:パッケージcom.itmayiedu。

クラスThreadTrain2はRunnableを実装して、{プライベートint型のカウント= 100; パブリックブールフラグ=真; プライベート静的オブジェクトOJ =新しいオブジェクト();

@Override
public void run() {
	if (flag) {

		while (count > 0) {

			synchronized (this) {
				if (count > 0) {
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						// TODO: handle exception
					}
					System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "票");
					count--;
				}
			}

		}

	} else {
		while (count > 0) {
			sale();
		}
	}

}

public synchronized void sale() {
	// 前提 多线程进行使用、多个线程只能拿到一把锁。
	// 保证只能让一个线程 在执行 缺点效率降低
	// synchronized (oj) {
	if (count > 0) {
		try {
			Thread.sleep(50);
		} catch (Exception e) {
			// TODO: handle exception
		}
		System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - count + 1) + "票");
		count--;
	}
	// }
}
复制代码

}

パブリッククラスThreadDemo2 {公共の静的な無効メイン(文字列[]引数)が例外:InterruptedExceptionをスロー{ThreadTrain2 threadTrain1 =新しいThreadTrain2();スレッドT1 =新しいスレッド(threadTrain1、 "①ウィンドウ番号");スレッドT2 =新しいスレッド(threadTrain1を、「②特許ウィンドウ「); t1.start();のThread.sleep(40); threadTrain1.flag = FALSE; t2.start();}} 5、静的同期機能5.1静的同期機能は何ですか?

  1. プラス静的(/「stætɪk/)キー、または.classファイルに基づいて修正された方法を使用して同期キーワードを使用。
  2. 静的ロック同期機能は、関数がバイトコードファイルオブジェクトに属し使用しています
  3. getClassメソッドによって得ることができる、あなたはまた、現在のクラス名の.class表現を使用することができます。コード:同期(ThreadTrain.class){System.out.printlnは(にThread.currentThread()のgetName()+ "の販売" +(100 - trainCount + 1)+。 "チケット"); TrainCount--。 {のThread.sleep(100);}試みるキャッチ(例外e)を{}}概要:現在のロックこのロックを変更する方法を使用して同期。変更されたバイトコードファイルロックを使用して同期の静的メソッドは、現在のクラスです。マルチスレッドデッドロック3.1は、マルチスレッドのデッドロックのAは何ですか:同期ネストされた同期、ロックにつながることは、コードリリースすることができません:パッケージcom.itmayieduを。

パブリックブール・フラグ= TRUE;プライベートオブジェクトミューテックス=新しいオブジェクト()クラスThreadTrain6はRunnableを{//これは、投票の貨物運送状の総数であり、複数のスレッドが同時にプライベートリソースを共有することができるINT trainCount = 100を実装します。

@Override
public void run() {
	if (flag) {
		while (true) {
			synchronized (mutex) {
				// 锁(同步代码块)在什么时候释放? 代码执行完, 自动释放锁.
				// 如果flag为true 先拿到 obj锁,在拿到this 锁、 才能执行。
				// 如果flag为false先拿到this,在拿到obj锁,才能执行。
				// 死锁解决办法:不要在同步中嵌套同步。
				sale();
			}
		}
	} else {
		while (true) {
			sale();
		}
	}
}

/**
 * 
 * @methodDesc: 功能描述:(出售火车票)
 */
public synchronized void sale() {
	synchronized (mutex) {
		if (trainCount > 0) {
			try {
				Thread.sleep(40);
			} catch (Exception e) {

			}
			System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");
			trainCount--;
		}
	}
}
复制代码

}

パブリッククラスDeadlockThread {

public static void main(String[] args) throws InterruptedException {

	ThreadTrain6 threadTrain = new ThreadTrain6(); // 定义 一个实例
	Thread thread1 = new Thread(threadTrain, "一号窗口");
	Thread thread2 = new Thread(threadTrain, "二号窗口");
	thread1.start();
	Thread.sleep(40);
	threadTrain.flag = false;
	thread2.start();
}
复制代码

}

図4に示すように、マルチスレッドは、3つの特性を有しています

  1. アトミック操作またはすべてまたはnoneのいずれかで動作する複数の実行行います。
  2. 可視性プライベートメモリの変更は、メインメモリに時間的に同期することができ、その民間所有者の可視一貫性を確保するために、
  3. コードシーケンスに従って実行シーケンスプログラムを注文。

すなわち、1つ以上の操作のいずれかのすべての操作が実行され、実行は任意の要因によって中断されることはありません、または実行しないように、原子は何4.1。古典的な例は、銀行振込みの問題である:考慮して、アカウントA、Bから千元プラス千元マイナス:例えば、B千元を考慮して、アカウントAから転送し、それは2つの操作を含める必要があります。これらの2つの操作が、いくつかの予期しない問題があることを保証するために、原子性を持っている必要があります。また、我々このようなI = I + 1と真オペレーショナルデータ、; iは書き込まIの読み出し値を含む、Iが算出されます。Javaでこのコード行は、マルチスレッド実行は問題があるでしょう原子性を持っていないので、我々は、同期を使用して確認してこの機能を作るためにこれらの事をロックする必要があります。実際には不可分、スレッドはこの変数の値を変更し、他のスレッドが直ちに変更された値を確認することができ、複数のスレッドが同じ変数にアクセス視認性が何であるか、一貫性のあるデータ、セキュリティ・スレッドの一部、4.2を確保します。別のCPUに2つのスレッド場合は、表示されませんでした、それはiの値を肯定する前に、まだある、変数のスレッド1、スレッド1は、メインメモリ、スレッド2をリフレッシュするためにスレッドを変更しなかったiの値を変更し、私が使用してこれは問題の可視性です。4.3注文コードでの実行を注文実行の順序はどのようなものです。プロセス効率を向上させるために一般的なプロセッサでは、コードの最適化を入力するかもしれない、それはコードの順序と一致するために、個々の文でプログラムの実行を保証するものではないが、それは、最終的なプログラムの実行及びコードシーケンスの結果ことを保証します結果は同じです。次のように:int型、A = 10; //ステートメントの1 int型のR = 2; //ステートメント2、A = A + 3; //ステートメント3、R = A *; //ステートメントの4ので並べ替え、彼が実行を命ずることができますしかし2-1-3-4,1-3-2-4 2-1-4-3にそうではない、それは依存関係を壊すので。明らかに、並べ替え、単一のスレッドがすべての問題を持っているつもりが、必ずしもではない、マルチスレッドので、我々は、マルチスレッドプログラミングの時にこの問題を検討する必要がされていません。

五、Javaのメモリモデル

共有メモリモデルは、Javaメモリモデル(JMMをいう。)を意味し、JMMは共有変数への1つのスレッドを書くことを決めた、それは別のスレッド上で見ることができます。メインメモリ(主記憶装置)、各スレッドがプライベートローカルメモリ(ローカルメモリ)を有し、スレッド変数ストレージ間で共有:ビューの抽象的な点から、JMMはスレッドとメインメモリとの間の抽象関係を定義します、ローカルメモリが共有変数を読み出し/書き込みするスレッドのコピーを保存します。JMMローカルメモリは抽象的な概念であり、本物ではないです。これは、キャッシュ、書き込みバッファ、レジスタとその他のハードウェアおよびコンパイラの最適化をカバーしています。

マップビューから、スレッドAとBの間のスレッドが伝達されるようです、それは以下の2つのステップを経る必要があります。

  1. まず、更新スレッドローカルメモリAは、メインメモリにフラッシュする変数を共有しました。
  2. 次に、スレッドAは、共有変数を更新する前にメインメモリに読み込むため、スレッドB。次の2つの手順によって例示するための模式図。

上記のように、A及びBは、共有変数xのメインメモリコピーでローカル・メモリを有します。初期仮定すると、これら3つのメモリのxの値は0です。一時A.で自身のローカルメモリに格納されたスレッドは、実行されると、(1の値を仮定して)は、xの値を更新します スレッドAおよびスレッドBが通信を必要とする場合、スレッドは、xの最初の値は、ローカルメモリの変更後、メインメモリにフラッシュ所有し、このときのxの値は、メインメモリは1となります。その後、スレッドBのローカルメモリも1になるこの時点で、更新スレッドAの後にxの値をxの値を読み取るためにメインメモリにスレッドB。全体として、この2つのステップ実質的スレッドにおけるスレッドがBにメッセージを送信し、通信処理をメインメモリを介して行かなければなりません。メモリ保証Javaプログラマの可視性を提供するために、メインメモリと、各スレッドのローカルメモリの間の相互作用を制御することにより、JMM。概要:Javaのメモリモデルとは何ですか:Javaのメモリモデルは、JMMを呼び、それがスレッドが別のスレッドに表示され定義されています。メインメモリに保存されている共有変数スレッド安全性の問題が発生したように、複数のスレッドが、メインメモリへのタイムリーなリフレッシュローカルメモリではない可能性があるデータにアクセスすると、各スレッドは、独自のローカルメモリを持っています。

六、揮発性の達成視界スレッド

volatileキーワードの役割は、目に見える複数のスレッド間で変数であるが、原子性を保証するものではありません、の次の記事リンクは非常に良い、ここでは詳細に説明しないjuejin.im/post/5afd22 ...

六、のAtomicInteger原子クラス

AtomicIntegerは、スレッドセーフな方法でアトミック操作Integerクラス、加算および減算動作を提供します。ここでの結果を比較例は、カウントの下で実行することができているとのAtomicIntegerが実行されている回数に関係なく、のAtomicInteger結果が正しいパッケージコムあることがわかります。

輸入java.util.concurrent.atomic.AtomicInteger。

パブリッククラスVolatileNoAtomicは、Thread {静的int型のカウント= 0を拡張し、プライベート静的のAtomicIntegerのAtomicInteger =新しいのAtomicInteger(0);

@Override
public  void  run() {
	for (int i = 0; i < 1000; i++) {
		//等同于i++
		atomicInteger.incrementAndGet();
		count++;
	}
	System.out.println(atomicInteger+","+count);
}

public static void main(String[] args) {
	// 初始化10个线程
	VolatileNoAtomic[] volatileNoAtomic = new VolatileNoAtomic[10];
	for (int i = 0; i < 10; i++) {
		// 创建
		volatileNoAtomic[i] = new VolatileNoAtomic();
	}
	for (int i = 0; i < volatileNoAtomic.length; i++) {
		volatileNoAtomic[i].start();
	}
}
复制代码

上記は、単にクラス原子を記述}、以下のリンクで詳細な表情はよく言うかもしれblog.csdn.net/xiaoliuliu2を...

七、揮発性(/ 'vɒlətaɪl/)と同期(/' sɪŋkrənaɪzd/)の違い

単独の揮発性は、セキュリティスレッドを保証することはできません。(原子)は、軽量①volatile、変数のみを変更することができます。変数揮発性の変更はブロックされませんので、ヘビー級を同期し、また修正された方法の②volatileは、データのみの可視性を保証することができ、複数のスレッドによる同時アクセスを同期するために使用することはできません。視認性を確保するために、ほかのスレッドが唯一のクリティカルセクションを入力するにはロックを取得することができますので、すべての文の実行のすべての重要な領域であることを確認するために、原子性を確保するためだけでなく、同期。複数のスレッドが同期ロックオブジェクトを競うときに、ブロッキングが発生します。スレッドセーフスレッドの安全性は二つの側面、①の視認性を含んでいます。②アトミック。上記の例から成長から見ることができます。唯一のスレッドの安全性を保証するものではありません揮発性を使用しています。そして、セキュリティスレッドを達成するために同期させることができます。八、ThreadLocalの深さ分析www.imooc.com/article/255 ...

おすすめ

転載: juejin.im/post/5d17050ee51d4550723b1437