プログラムは、通常、複数のスレッドが含まれている、時間に起動して実行を処理するために変換されます。
典型的には、多くの場合、解決するために、複数のスレッドを使用して(例えば、長いループ、ファイルのアップロードとダウンロード、ネットワークリソースへのアクセスなど)の処理時間がかかる操作。
例えば、ディスプレイの寿命は、銀行のお金の問題、問題複数の列車の切符のウィンドウは、通常、マルチスレッド技術を必要と同時実行の問題を伴います。
このプロセスは、コードブロックの重要なデータを入力する複数の並行スレッドを持っている場合は、異常なデータが得られ、スレッドの安全性の問題につながる可能性が高いプロセス内のデータを、変更します。たとえば、通常のロジックについては、同じ数のチケットは一度だけ販売、しかしためのセキュリティスレッドは、実際のビジネスの例外につながっ数回、販売されています。
今、私たちは発券スレッド安全性の問題を実証する必要があり
1、マルチスレッドのデータ保護の場合の状況につながりません
パブリッククラスThreadUnSecurity { 静的int型チケット= 10。 クラスSellTicketsを実装したRunnable { @Override ます。public void実行(){ //未加同步时产生脏数据 しばらく(チケット> 0){ System.out.printlnは(にThread.currentThread()。のgetName()+ "--->售出第: "+チケット+"票"); 切符売場 - ; {試す のThread.sleep(1000); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } もし(チケット<= 0){ System.out.printlnは(にThread.currentThread()のgetName()+ "---> チケット販売終了!「); } } } (文字列[]引数){主パブリック静的ボイド 。SellTicketsは、(=新しいThreadUnSecurityを販売する)新しいSellTickets()。 =新しいスレッド(売る、 "1号を窗口")スレッド1スレッド。 =新しいスレッドをスレッド2スレッド(、 "2号を窗口"売ります)。 =新しいスレッド(売る、 "3号を窗口")thread3スレッド。 =新しいスレッド(売る、 "4号を窗口")thread4スレッド。 thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
コードの実行結果:
ウインドウ番号1 --->の販売:10票 10票:--->の販売3ウィンドウ 10のチケット:--->の販売ランク2ウィンドウ 4 --->の販売ウィンドウ。 10票 の販売ランク2ウィンドウ--->:6票 5票:第1ウィンドウ--->は、販売 4のチケット:の販売窓3 ---> 販売窓4 --->第3票 番号2ウィンドウ--->最初の販売:2チケット 窓4を--->最初の販売:1票 番号1ウィンドウは--->最初の販売:1投票 3ウィンドウ--->チケット販売終了! 第2ウィンドウ] ---> [エンドチケット! 第1ウィンドウ--->エンドチケット! 第4窓--->エンドチケット!
私たちは、同じチケットが投票権数を保護するために複数回販売されるだろうと同じチケットを見ることができます!上記のコードを提示しながらによるスレッドのスケジューリングの不確実性、読者に、結果が異なることがあります表示されます。
最初の実装スレッドセーフな方法
シンクブロック
パッケージcom.bpan.spring.beans.thread。 輸入com.sun.org.apache.regexp.internal.recompile。 パブリッククラスThreadSynchronizedSecurity { 静的int型チケット= 10。 クラスSellTicketsはRunnableを実装して、{ @Override ます。public void実行(){ //同步代码块 しばらく(チケット> 0){ 同期(本){ //するSystem.out.println(this.getClass()。のgetName()。のtoStringを( )); IF(チケットは<= 0){ 返します。 } のSystem.out.println(にThread.currentThread()のgetName()+ "--->售出第: "+チケット+"票")。 切符売場 - ; {試みる のThread.sleep(100)。 }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } もし(チケット<= 0){ System.out.printlnは(にThread.currentThread()のgetName()+。 "--->售票结束!")。 } } } } (文字列[]引数){主パブリック静的ボイド SellTicketsは、(=新しいThreadSynchronizedSecurityを販売する)新しいSellTickets()。 =新しいスレッド(売る、 "1号を窗口")スレッド1スレッド。 =新しいスレッドをスレッド2スレッド(、 "2号を窗口"売ります)。 =新しいスレッド(売る、 "3号を窗口")thread3スレッド。 =新しいスレッド(売る、 "4号を窗口")thread4スレッド。 thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
読者は、状況は同じチケットが発生していない何回も販売され、出力をデバッグするのは自由です。
第二の方法
同期方法
パッケージcom.bpan.spring.beans.thread。 パブリッククラスThreadSynchroniazedMethodSecurity { 静的int型チケット= 10。 クラスSellTicketsは実装したRunnable { @Override ます。public void実行(){ //同步方法 しばらく(チケット> 0){ synMethod(); {試みる のThread.sleep(100)。 }キャッチ(InterruptedExceptionある電子){ // TODO自動生成キャッチブロック e.printStackTrace(); } IF(チケット<= 0){ } System.out.printlnは(にThread.currentThread()のgetName()+ "---售票结束。>")。 } } スレッドthread3は=新しいスレッド(売ります、 " 同期ボイドsynMethod(){ 同期(本){ IF(チケット<= 0){ 返します。 } のSystem.out.println(にThread.currentThread()のgetName()+ "---->售出第"+チケット+"票"。)。 切符売場 - ; } } } パブリック静的無効メイン(文字列[] args){ SellTicketsは、(=新しいThreadSynchroniazedMethodSecurityを販売する)新しいSellTickets()。 =新しいスレッド(売る、 "1号を窗口")スレッド1スレッド。 =新しいスレッドをスレッド2スレッド(、 "2号を窗口"売ります)。 =新しいスレッド(売る、 "4号を窗口")thread4スレッド。 thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
読者は自分の業績上記のコードをデバッグすることができます
第三の方法
ロックロック機構は、ロック()ロックを使用して作成されたロックオブジェクトが、)(アンロック特定のコードブロックを保護するためにロックを解除します
パッケージcom.bpan.spring.beans.thread。 輸入java.util.concurrent.locks.Lock。 輸入java.util.concurrent.locks.ReentrantLock。 パブリッククラスThreadLockSecurity { 静的int型チケット= 10。 クラスSellTicketsはRunnableを{実装 ロックロック=新しいReentrantLockのを(); @Override ます。public void実行(){ //ロック锁机制 ながら(チケットは> 0){ {みてください )(lock.lockを。 IF(チケットは<= 0){ 返します。 } のSystem.out.println(にThread.currentThread()のgetName()+ "--->售出第: "+チケット+"票")。 tickets--。 }キャッチ(例外E1){ // TODO自動生成されたcatchブロックの e1.printStackTrace(); }最後に{ lock.unlock()。 {試みる のThread.sleep(100)。 }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } } もし(チケット<= 0){ System.out.printlnは(にThread.currentThread()のgetName()+。 "--->售票结束!")。 } } } パブリック静的無効メイン(文字列[] args){ SellTicketsは)(=新しいThreadLockSecurityを販売する新しいSellTicketsを()。 =新しいスレッド(売る、 "1号を窗口")スレッド1スレッド。 =新しいスレッドをスレッド2スレッド(、 "2号を窗口"売ります)。 =新しいスレッド(売る、 "3号を窗口")thread3スレッド。 =新しいスレッド(売る、 "4号を窗口")thread4スレッド。 thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
彼は結論付けました。
JVMで達成レベルが同期されているので、システムにロック解除か否かを監視することができる。ReentrantLockの、コードを使用して実装され、システムが自動的に最終的に節lock.unlockが明示的に(コードでロックを解除し、それが必要であるロックを解除することができません)。
また、同期の同時使用の場合よりも小さいが良い選択である。しかし、場合よりも高い同時実行で、それは非常に深刻なパフォーマンスの低下となり、この時間ReentrantLockのは良いプログラムです。
彼は加えました:
同期コードブロックを使用しているとき(待機して使用してもよい)、()通知、 nitifyAll()、 一層通信スレッド。
これは、待って()他のスレッドがロックをつかむために待っている間、この方法は、プログラムのロックを実行するためのスレッドを取得し、待機プール、リリースCPU、に、現在のスレッドをオブジェクトロックの所有権を解放します。睡眠のスレッド()メソッドがあります現在のスレッドが一時的にCPUを解放し、睡眠中に、いくつかの時間をスリープ状態にはなく、オブジェクトのロックを解除しないと述べたが、それは、睡眠中に、他のスレッドは、まだ眠りに現在のスレッドの保護終わりを同期した内部コードを入力することはできませんさCPUは、同期保護コードを実行するために、実行する権利を取り戻すだろう。
待って()と睡眠()は、オブジェクトのロックを解除し、睡眠()は、オブジェクトのロックを解除しません)(最大の違い待ちです。
通知()メソッドは、スレッドがオブジェクトのロックを獲得する機会を有するようにオブジェクト()は、待機状態であるため待機を呼び出すスレッドを起動します。()通知を呼び出した後、現在のスレッドがオブジェクトのロックを解除し、直ちにロックを解除するが、完全に実行される同期コードまで、現在のコードの実行を継続しないであろう。JVMは、ロックは、オブジェクトを取得するために、コードを実行待機中のスレッドにスレッドを送出します。
なお、待って()と通知()同期化コードブロックと呼ばれる必要があります。
notifyAll()ウェイクアップ、すべての待機中のスレッドです。
以下は、サンプルコードであります
com.bpan.spring.beans.threadパッケージ; publicクラスThreadDemo { 静的な最終的なオブジェクトOBJ =新しい新しいオブジェクト(); //最初の子スレッド スレッドAにおける静的クラスを実装したRunnable { @Override ます。public void RUN(){ int型= 10 COUNT ; 一方(COUNT> 0){ 同期(ThreadDemo.obj){ System.out.printlnは( "A -----" + COUNT); count--; 同期(ThreadDemo.obj){ //通知()メソッドスレッドがオブジェクトのロックを獲得する機会を持つように、待機状態で呼び出し、オブジェクトの待機理由は()とスレッドを覚まします。 //)が(通知を呼び出し、同期コードが完全に実行されるまで、現在のスレッドはすぐに、ロックを解除しますが、現在のコードの実行を継続しません。 ThreadDemo.obj.notify(); 試み{ ThreadDemo.obj.wait(); }キャッチ(InterruptedExceptionある電子){ // TODO自動生成キャッチブロック e.printStackTrace(); } } } } } } 静的クラスThreadB Runnableを{実装 @Override 公共ボイドラン(){ int型のカウント= 10。 (> 0のカウント){ながら (ThreadDemo.obj)同期{ するSystem.out.println( "B -----" +カウント)。 count--。 同期(ThreadDemo.obj){ スレッドがオブジェクトのロックを獲得する機会を持つように//通知()メソッドは、あるため、待機()とスレッドの待機状態でオブジェクトの航跡を呼び出します。 //同期コードが完全に実行されるまで、現在のスレッドが直ちにロックを解除するが、現在のコードの実行を継続しない、)(通知呼び出し、 ThreadDemo.obj.notify(); 試み{ ThreadDemo.obj.wait() ; }キャッチ(InterruptedExceptionあるE){ // TODO自動生成されたブロックキャッチ e.printStackTrace(); } } } } } } パブリック静的無効メイン(文字列[] args){ 新しいスレッド(新しいスレッドA())(開始)。 新しいスレッド(新しいThreadB())(開始)。 } }