0。ミューテックスについて
いわゆるMutexロックは、一度に1つのスレッドしか持たないロックを指します。 JDK1.5の前に、通常、同期メカニズムを使用して、複数のスレッドのアクセスを共有リソースに制御しました。現在、ロックは、同期されたメカニズムよりも幅広いロック操作を提供します。ロックと同期メカニズムの主な違い:
同期されたメカニズムは、各オブジェクトに関連付けられた暗黙のモニターロックへのアクセスを提供し、すべてのロック取得と解放をブロック構造に表示するように強制します。複数のロックが取得される場合、それらは逆の順序で解放する必要があります。同期されたメカニズムは、ロックを暗黙的に放出します。コードがスレッドによって実行されると、同期されたステートメントブロックの範囲を超える限り、ロックがリリースされます。ロックメカニズムは、ロックオブジェクトのUnlock()メソッドを明示的に呼び出してロックを放出する必要があります。これにより、ロックの取得と放出が同じブロック構造に表示されない可能性があり、ロックをより自由な順序で放出します。
1。ReentrantLockの紹介
ReentrantLockは、「排他的ロック」とも呼ばれるReentrant Mutex Lockです。
名前が示すように、ReentrantLockロックは同じ時点で1つのスレッドロックによってのみ保持できます。一方、リエントラントとは、ReentrantLockロックを単一のスレッドで複数回取得できることを意味します。
ReentrantLockは、「フェアロック」と「不公平なロック」に分割されます。それらの違いは、ロックを取得するメカニズムが公正かどうかに反映されています。 「ロック」とは、競合するリソースを保護し、複数のスレッドが同時にスレッドとエラーを操作するのを防ぐことです。 ReentrantLockは、1つのスレッドによってのみ同時に取得できます(スレッドが「ロック」を取得する場合、他のスレッドが待つ必要があります)。 ReentraantLockは、FIFO待機キューを介してロックを取得するすべてのスレッドを管理します。 「フェアロック」のメカニズムの下で、スレッドがキューアップしてロックインシーケンスを取得します。一方、「フェア以外のロック」は、キューの先頭にあるかどうかに関係なく、ロックを取得します。
REENTRANTLANTLOCK機能リスト
//デフォルトで「不公平なロック」であるReentrantLockを作成します。 ReentrantLock()//作成ポリシーは、フェアのREENTRANTLOCKです。公正が真実である場合、それはそれが公正なロックであり、フェアが間違っている場合、それはそれがフェア以外のロックであることを意味します。 REENTRANTLOCK(BOOLEAN FAIR)//現在のスレッドがこのロックを維持している回数をクエリします。 int getholdcount()//このロックを所有しているスレッドを返します。このロックが任意のスレッドで所有されていない場合は、nullを返します。 Protected Thread getOwner()//このロックの取得を待っている可能性のあるスレッドを含むコレクションを返します。 Protected Collection <thread> getQueuedThreads()//このロックを取得するのを待っているスレッドの推定数を返します。 int getqueuelength()//このロックに関連する特定の条件を待っている可能性のあるスレッドを含むコレクションを返します。保護されたコレクション<thread> getWaitingThreads(状態条件)//このロックに関連する特定の条件を待っているスレッド推定値を返します。 int getWaitqueuelength(条件条件)// Query与えられたスレッドがこのロックの取得を待っているかどうか。 boolean hasqueuedthread(スレッドスレッド)//クエリいくつかのスレッドがこのロックの取得を待っているかどうか。 boolean hasqueuedthreads()//クエリいくつかのスレッドがこのロックに関連する特定の条件を待っているかどうか。 Boolean Haswaiters(状態条件)//「フェアロック」の場合はtrueを返し、それ以外の場合はFalseを返します。 boolean isfair()// query現在のスレッドがこのロックを維持するかどうか。 boolean isheldbycurrentthread()//クエリこのロックが任意のスレッドによって保持されているかどうか。 boolean islocked()//ロックを取得します。 void lock()//現在のスレッドが中断されない場合、ロックが取得されます。 boid lockinterractibly()//このロックインスタンスで使用するために使用される条件インスタンスを返します。 Condition NewCondition()//呼び出し中に別のスレッドによって保持されていない場合にのみロックを取得します。 boolean trylock()//ロックは、特定の待機時間内に別のスレッドによって保持されず、現在のスレッドが中断されない場合、ロックが取得されます。 Boolean TryLock(Long Timeout、TimeUnit Unit)//このロックを解放しようとします。 void lrock()
2。ReentrantLockの例
「例1」と「例2」を比較することにより、ロックとロックを解除する役割を明確に理解できます
2.1例1
java.util.concurrent.locks.lock; Import java.util.concurrent.locks.reentrantlock; // locktest1.java//リポジトリクラスdepot {private int size; //リポジトリのプライベートロックロックの実際の数。 //排他的ロックpublic depot(){this.size = 0; this.lock = new ReentrantLock(); } public void produce(int val){lock.lock(); {size += val; system.out.printf( "%sプロダクト(%d) - > size =%d/n"、thread.currentthread()。getname()、val、size); }最後に{lock.unlock(); }} public void consust(int val){lock.lock(); {size- = val; System.out.printf( "%s消費(%d)< - size =%d/n"、thread.currentthread()。getname()、val、size); }最後に{lock.unlock(); }}}; //プロデューサークラスプロデューサー{プライベートデポデポジット;パブリックプロデューサー(Depot Depot){this.depot = dopit; } //消費者製品:倉庫に製品を生産する新しいスレッドを作成します。 public void produce(final int val){new Thread(){public void run(){dosit.produce(val); } }。始める(); }} // Consumer Class Customer {Private Depot Deposit;パブリックカスタマー(Depot Depot){this.depot = deposit; } //消費者製品:倉庫から製品を消費する新しいスレッドを作成します。 public void consumption(final int val){new Stread(){public void run(){depot.consume(val); } }。始める(); }} public class locktest1 {public static void main(string [] args){depot mdepot = new depot();プロデューサーmpro = new Producer(mdepot);顧客MCUS = New Customer(MDEPOT); mpro.produce(60); mpro.produce(120); MCUS.CONSUME(90); MCUS.CONSUME(150); mpro.produce(110); }}実行結果:
スレッド-0プロデュース(60) - > size = 60thread-1プロデュース(120) - > size = 180thread-3消費(150)< - サイズ= 30thread-2消費(90)< - サイズ= -60thread-4生成(110) - > size = 50
結果分析:
(1)デポは倉庫です。商品は農産物()を介して倉庫に生産でき、倉庫内の商品は消費()を通じて消費できます。倉庫への相互に排他的なアクセスは、排他的なロックロックを通じて達成されます。倉庫で商品を運転する前に(生産/消費)、倉庫は最初にlock()を介してロックされ、操作が完了した後にUnlock()を介してロック解除されます。
(2)プロデューサーはプロデューサーです。プロデューサーのプロデュース()関数を呼び出すと、新しいスレッドを作成して倉庫で製品を生産できます。
(3)顧客は消費者カテゴリです。顧客の消費()関数を呼び出すと、倉庫に新しいスレッド消費製品を作成できます。
(4)メインスレッドメインでは、新しい生産者MPROと新しい消費者MCUを作成します。それらはそれぞれ倉庫に製品を生産/消費します。
主な生産/消費量によると、倉庫内の最終的な残りの製品は50でなければなりません。操作の結果は私たちの期待に沿っています!
このモデルには2つの問題があります。
(1)実際には、倉庫の容量は負にすることはできません。ただし、このモデルの倉庫容量は否定的である可能性があり、現実と矛盾しています!
(2)実際には、倉庫の容量は限られています。ただし、このモデルの容量に本当に制限はありません!
これら2つの問題を解決する方法について簡単に説明します。それでは、最初に簡単な例2を見てみましょう。 「例1」と「例2」を比較することにより、Lock()とUnlock()の目的をより明確に理解できます。
2.2例2
java.util.concurrent.locks.lock; import java.util.concurrent.locks.reentrantlock; // locktest2.java//リポジトリクラスdepot {private int size; //リポジトリのプライベートロックロックの実際の数。 //排他的ロックpublic depot(){this.size = 0; this.lock = new ReentrantLock(); } public void produce(int val){// lock.lock(); // try {size += val; System.out.printf( "%sプロデューション(%d) - > size =%d/n"、thread.currentthread()。getName()、val、size); //} catch(arternedexception e){//}最後に{// lock.unlock(); //}} public void conductstion System.out.printf( "%s Consume(%d)< - size =%d/n"、thread.currentthread()。getname()、val、size); //}最後に{// lock.unlock(); //}}}; //プロデューサークラスプロデューサー{プライベートデポ預金;パブリックプロデューサー(デポデポジット){this.depot = deposit; } //消費者製品:新しいスレッドを作成して、製品を倉庫に生成します。 public void produce(final int val){new Thread(){public void run(){dosit.produce(val); } }。始める(); }} // Consumer Class Customer {Private Depot Deposit;パブリックカスタマー(Depot Depot){this.depot = deposit; } //消費者製品:倉庫から製品を消費する新しいスレッドを作成します。 public void consumption(final int val){new Stread(){public void run(){depot.consume(val); } }。始める(); }} public class locktest2 {public static void main(string [] args){depot mdepot = new depot();プロデューサーmpro = new Producer(mdepot);顧客MCUS = New Customer(MDEPOT); mpro.produce(60); mpro.produce(120); MCUS.CONSUME(90); MCUS.CONSUME(150); mpro.produce(110); }} (一度)結果:
スレッド-0プロデュース(60) - > size = -60thread-4プロデュース(110) - > size = 50thread-2消費(90)< - size = -60thread-1生成(120) - > size = -60thread-3消費(150)< - サイズ= -60
結果説明:
「例2」は、「例1」に基づいてロックロックを削除します。例2では、倉庫に残っている最終製品は-60であり、予想される50ではなく。その理由は、リポジトリへのMutexアクセスを実装しないためです。
2.3例3
「例3」では、「例1」の2つの問題を解決するために条件を使用します。「倉庫の容量は否定的ではない」、「倉庫の能力は限られています」。
この問題の解決策は条件によるものです。条件は、lock:await()メソッドと条件で使用する必要があります。条件の信号()方法により、ウェイクアップスレッドが[notify()と同様]を引き起こす可能性があります。
java.util.concurrent.locks.lock; import java.util.concurrent.locks.reentrantlock; import java.util.concurrent.locks.condition; // locktest3.java// warehouse class depot {private int capuation; //倉庫容量プライベートINTサイズ。 //倉庫のプライベートロックロックの実際の数。 //専用のロックプライベートコンディションフルコンディション。 //生産条件私的条件Emptycondition; //消費条件パブリックデポ(int容量){this.capacity = carpity; this.size = 0; this.lock = new ReentrantLock(); this.fullcondtion = lock.newcondition(); this.emptycondition = lock.newcondition(); } public void produce(int val){lock.lock(); try {//左は「生産したい量」(生産量が多すぎる可能性があるため、より多く生産する必要があるかもしれません)を意味します。 (左> 0){//在庫がいっぱいの場合、「消費者」が製品を消費するのを待ちます。 while(size> =容量)fullcondtion.await(); //「実際の生産量」(つまり、在庫に追加された新しい数量)を取得します//「在庫」 +「希望する生産数量」>「総容量」、「実際の増分」=「総容量」 - 「現在の容量」。 (現時点で倉庫に入力してください)//それ以外の場合は、「実際の増分」=「生産する数量 "int inc =(size+left)>容量? (キャパシティサイズ):左; size += inc;左 - = inc; System.out.printf( "%sプロデューション(%3D) - > left =%3D、inc =%3d、size =%3d/n"、thread.currentthread()。 //「消費者」に消費できることを通知します。 emptycondtion.signal(); }} catch(arturtedexception e){} fullly {lock.unlock(); }} public void consust(int val){lock.lock(); try {//左は「消費される消費量」を意味します(大きすぎる可能性があり、在庫は十分ではないので、もっと消費する必要があります)int左= val; (左> 0){//インベントリが0の場合、「プロデューサー」が製品を生産するのを待ちます。 while(size <= 0)emptycondtion.await(); //「実際の消費量」(つまり、在庫の実際の減少)を取得します//「在庫」<「顧客が消費したい数量」、「実際の消費」=「インベントリ」; //それ以外の場合、「実際の消費」=「顧客が消費したい量」。 int dec =(size <左)?サイズ:左;サイズ - = DEC;左 - = DEC; System.out.printf( "%s Consume(%3D)< - left =%3d、dec =%3d、size =%3d/n"、thread.currentthread()。 fullcondtion.signal(); }} catch(arturtedexception e){} fullly {lock.unlock(); }} public String toString(){return "caperation:"+caperage+"、実際のサイズ:"+size; }}; //プロデューサークラスプロデューサー{プライベートデポデポジット;パブリックプロデューサー(デポデポジット){this.depot = deposit; } //消費者製品:新しいスレッドを作成して、製品を倉庫に生成します。 public void produce(final int val){new Thread(){public void run(){dosit.produce(val); } }。始める(); }} // Consumer Class Customer {Private Depot Deposit;パブリックカスタマー(Depot Depot){this.depot = deposit; } //消費者製品:倉庫から製品を消費する新しいスレッドを作成します。 public void consumption(final int val){new Stread(){public void run(){depot.consume(val); } }。始める(); }} public class locktest3 {public static void main(string [] args){depot mdepot = new Depot(100);プロデューサーmpro = new Producer(mdepot);顧客MCUS = New Customer(MDEPOT); mpro.produce(60); mpro.produce(120); MCUS.CONSUME(90); MCUS.CONSUME(150); mpro.produce(110); }} (一度)結果:
スレッド-0プロデュース(60) - >左= 0、inc = 60、size = 60thread-1プロデュース(120) - > left = 80、inc = 40、size = 100thread-2消費(90)< - 左= 0、dec = 90、size = 10thread-3消費消費(150)< - 左= 40、dec = 100、size = 0thread-4プロデュース(110) - > left = 0、inc = 10、size = 10thread-3消費(150)< - 左= 30、dec = 10、size = 0thread-1生成(120) - >左= 0、inc = 80、size