なぜスレッドの同期
変数またはオブジェクトに同時にアクセスする複数のスレッドがある場合、これらのスレッドに読み取り操作と書き込み操作の両方がある場合、変数値またはオブジェクトステータスに混乱を引き起こし、プログラムの例外になります。たとえば、銀行口座が同時に2つのスレッドで運用されている場合、1つは100元を引き出し、もう1つは100元を節約します。アカウントが元々0元を持っていたと仮定すると、引き出しスレッドと保存スレッドが同時に発生した場合はどうなりますか?お金の撤回が成功していない場合、口座残高は100です。お金の撤回が成功した場合、アカウント残高は0です。はっきりと説明するのは難しいです。したがって、マルチスレッドの同期は、この問題を解決することです。
1。同期していないときのコード
Bank.javaパッケージスレッドテスト; out .println(system.currenttimemillis()+"save:"+money); :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づ 火::::: :::::::::::::::::::); 「テイクアウト: "+money) (string args []){final Bank = new b ank(); new runnable(){ @ override public void run(){// todo auto-eneratedメソッドスタブ(true){try {sweet(1000); /n ");}}}); thread tsub = new swerch(new runnable(){@override public void run(){// todo auto-fienatedメソッドスタブwhile(true){bank.submoney(100); bank bank .luedmoney.out.println( "/n"); })tsub.start();
コードは非常にシンプルです、私はそれを説明しませんか?私はそれらのいくつかを傍受しました、それは非常に乱雑であり、私は文章を理解することができません。
不十分な残高口座残高:0
不十分な残高口座残高:100
1441790503354デポジット:100
アカウント残高:100
1441790504354デポジット:100
アカウント残高:100
1441790504354テイクアウト:100
アカウント残高:100
1441790505355デポジット:100
アカウント残高:100
1441790505355テイクアウト:100
アカウント残高:100
2。同期コードを使用します
(1)同期方法:
同期されたキーワードを変更する方法があります。 Javaの各オブジェクトにはロックが組み込まれているため、このキーワードでメソッドを変更すると、組み込みロックがメソッド全体を保護します。この方法を呼び出す前に、内蔵ロックを取得する必要があります。そうしないと、ブロッキング状態になります。
修正bank.java
実行中の結果を見てみましょう。
不十分な残高口座残高:0
不十分な残高口座残高:0
1441790837380Saved:100
アカウント残高:100
1441790838380テイクアウト:100
アカウント残高:0
1441790838380Saved:100
アカウント残高:100
1441790839381削除:100
アカウント残高:0
即座に理解していると感じています。
注:同期されたキーワードは、静的メソッドをこの時点で呼び出す場合、クラス全体がロックされます。
(2)コードブロックを同期します
つまり、同期されたキーワードによって変更されたステートメントブロックがあります。このキーワードによって変更されたステートメントブロックは、同期を実現するために内蔵ロックで自動的に追加されます
bank.javaコードは次のとおりです。
パッケージスレッドテスト; ** * @author ww * */private int count = 0; System.out.println(System.currenttimemillis()+"save:"+money}}} .println(「不十分なバランス」); {system.out.println( "account balance:"+count);
操作結果は次のとおりです。
不十分な残高口座残高:0
1441791806699Saved:100
アカウント残高:100
1441791806700テイクアウト:100
アカウント残高:0
1441791807699Saved:100
アカウント残高:100
効果はメソッドに似ています。
注:同期はハイオーバーヘッド操作であるため、同期されたコンテンツを最小限に抑える必要があります。通常、メソッド全体を同期する必要はありません。同期コードブロックを使用してキーコードを同期するだけです。
(3)特別なドメイン変数(揮発性)を使用して、スレッドの同期を実現する
A.Volatileキーワードは、ドメイン変数にアクセスするためのロックフリーメカニズムを提供します
b揮発性を使用してドメインを変更することは、ドメインが他のスレッドで更新される可能性があることを仮想マシンに伝えることに相当します。
cしたがって、フィールドを使用するたびに、レジスタの値を使用する代わりに、それを再計算する必要があります。
d.volatileは原子動作を提供しませんし、最終タイプの変数を変更するために使用することもできません
bank.javaコードは次のとおりです。
パッケージスレッドテスト; (system.currenttimemillis() + "save:" + money) ; count -= money.out.println( + currenttimemillis: " + money); " + count);}}
操作効果はどうですか?
不十分な残高口座残高:0
不十分な残高口座残高:100
1441792010959Saved:100
アカウント残高:100
1441792011960テイクアウト:100
アカウント残高:0
1441792011961Saved:100
アカウント残高:100
それは私が再びそれを理解できず、再び乱雑だからでしょうか?なぜこれがなぜですか?揮発性が原子動作を保証できないため、揮発性は同期したものに取って代わることができないためです。さらに、Volatileはコンパイラを整理してコードを最適化するため、使用できる場合は適用されません。その原則は、スレッドが揮発性によって変更された変数にアクセスしたい場合、キャッシュではなくメモリから読み取られるため、各スレッドでアクセスされる変数値は同じです。これにより、同期が保証されます。
(4)再突入ロックを使用して、スレッドの同期を実現します
同期をサポートするために、新しいjava.util.concurrentパッケージがjavase5.0に追加されました。 ReentrantLockクラスは、ロックインターフェイスを実装するリエントラントで相互に排他的なロックです。
Reenreantlockクラスの一般的な方法は次のとおりです。
ReentrantLock():ReentrantLockインスタンスを作成します
lock():ロックを取得します
Unlock():ReentrantLock注:ReentrantLock()には、公正なロックを作成できるコンストラクターもありますが、プログラムの実行効率を大幅に低下させるため、使用することはお勧めしません。
bank.javaコードは次のように変更されます。
パッケージスレッドテスト。 //このロックを宣言する必要があります= new ReentrantLock(); tln(system .currenttimemillis() + "save:" + money); if(money <0){system.out.println( "不十分なバランス"); ;最後に{lock.unlock()}
操作効果はどうですか?
不十分な残高口座残高:0
不十分な残高口座残高:0
1441792891934デポジット:100
アカウント残高:100
1441792892935Saved:100
アカウント残高:200
1441792892954テイクアウト:100
アカウント残高:100
効果は、最初の2つの方法に似ています。
同期されたキーワードがユーザーのニーズを満たすことができる場合、コードを簡素化できるため、同期して使用します。より高度な機能が必要な場合は、この時点でロックをリリースするように注意してください。
(5)ローカル変数を使用して、スレッドの同期を実現します
bank.javaコードは次のとおりです。
パッケージスレッドテスト; / ** * @author ww * * / public class bank {private statrelocal> count = new swreatlocal <integer>(){@override portated integer initialValue(){// todo auto-enerated method method stab return 0; ;) () - system.out.println( + currenttimemillis() + " + money); count());
ランニング効果:
不十分な残高口座残高:0
不十分な残高口座残高:0
1441794247939Saved:100
アカウント残高:100
バランスが不十分です
1441794248940Save:100
アカウント残高:0
アカウント残高:200
不十分な残高口座残高:0
1441794249941Saved:100
アカウント残高:300
操作効果を見た後、私は最初に混乱しました。 Threadlocalの原則を見てください:
スレッドローカルを使用して変数を管理する場合、変数を使用して各スレッドが変数のコピーを取得し、コピーは互いに独立しているため、各スレッドは他のスレッドに影響を与えることなく、変数の独自のコピーを自由に変更できます。今、私はそれがコピーを実行していることがわかりました。したがって、上記の効果が発生します。
threadlocalおよび同期メカニズム
A.ThreadLocalと同期メカニズムは、両方ともマルチスレッドで同じ変数のアクセス競合問題を解決することを目的としています
b前者は「時間の空間」の方法を採用し、後者は「スペースの時間」の方法を採用し、後者は「スペースの時間」の方法を採用しています。
今、私は理解しています。それぞれが独自の利点と短所を持ち、適用されるシナリオがあります。