同時生産者消費者の問題
AQS AbstractQueuedSynchronizer抽象クラスAQSはjavaで「ロック」を管理する抽象クラスであり、ロックの多くの共通の方法はこのクラスで実現されている.AQSは、排他的ロック(例えば、ReentrantLock)および共有ロック(例えば、Semaphore)の共通の親である.1.1排他ロックは、1つの時点で1つのスレッドロックによってのみ占有されます.ロックの取得メカニズムによって、「フェアロック」と「非フェアロック」に分けられます.1.1.1公平ロックは、CLH待ちスレッドを通じて先得の規則に従い、公平にロックを取得する.1.1.2非フェアロックの場合、スレッドがロックを取得しようとすると、CLH待ちキューを無視して直接ロックを取得します.排他ロックの典型的な例はReentrantLockであり、またReentrantReadWriteLock.WriteLockも排他ロックである.1.2共有ロックは、複数のスレッドによって同時に所有され、共有されるロックである.JUCパッケージのReentrantReadWriteLock.ReadLock,CyclicBarrier,CountDownLatch,Semaphoreは共有ロックです.これらのロックの用途と原理は,後で詳しく紹介する.
![画像アップロード中...]
ReentrantLock
ロックを採用する場合は、自分からロックを解除しなければなりません.ただし、異常が発生した場合、自動的にロックは解除されません.従って、一般的には、ロックの使用はtry{}catch{}で行う必要があり、ロックが必ず解放され、デッドロックが防止されるように、ロックを解放する操作をfinallyブロックに置く必要がある.
ロックを使用して同期を行う場合、形式は以下の通りです.
マルチスレッドが共有リソースを操作する場合、ロックを使用するには、生産者クラスmPro、消費者クラスmCusがあり、操作ごとにスレッドが作成されると仮定する必要があります.
排他ロックを使用しない場合は、
Condition
Conditionインタフェースには、ロックに関連付けられる可能性のある条件変数が記述されています.Conditionは、Objectモニタメソッドの代わりに、await()、signal()を使用してスレッドをスリープ/起動する役割を果たすロックと連携する必要があります.
例えば生産者-消費者問題では、資源が空いている場合、消費者は消費できない.共有資源がいっぱいになったとき、生産者は再生産できない.だからロックはConditionを借りる必要がある
![画像アップロード中...]
ReentrantLock
ロックを採用する場合は、自分からロックを解除しなければなりません.ただし、異常が発生した場合、自動的にロックは解除されません.従って、一般的には、ロックの使用はtry{}catch{}で行う必要があり、ロックが必ず解放され、デッドロックが防止されるように、ロックを解放する操作をfinallyブロックに置く必要がある.
ロックを使用して同期を行う場合、形式は以下の通りです.
Lock lock = ...;
lock.lock(); //
try{
//
}catch(Exception ex){
}finally{
lock.unlock(); //
}
マルチスレッドが共有リソースを操作する場合、ロックを使用するには、生産者クラスmPro、消費者クラスmCusがあり、操作ごとにスレッドが作成されると仮定する必要があります.
mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
排他ロックを使用しない場合は、
Thread-0 produce(60) --> size=-60 Thread-4 produce(110) --> size=50 Thread-2 consume(90) size=-60 Thread-3 consume(150)
1 size +60, println , 2, 120, , 90 150 1 , size -60 。
が発生する可能性があります.Condition
Conditionインタフェースには、ロックに関連付けられる可能性のある条件変数が記述されています.Conditionは、Objectモニタメソッドの代わりに、await()、signal()を使用してスレッドをスリープ/起動する役割を果たすロックと連携する必要があります.
例えば生産者-消費者問題では、資源が空いている場合、消費者は消費できない.共有資源がいっぱいになったとき、生産者は再生産できない.だからロックはConditionを借りる必要がある
private Condition fullCondtion; //
private Condition emptyCondtion; //
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
class Depot{
private int capacity; //
private int size; //
private Lock lock; //
private Condition fullCondition; //
private Condition emptyCondition; //
public Depot(int capacity) {
this.capacity = capacity;
this.size = 0;
this.lock = new ReentrantLock();
this.fullCondition = lock.newCondition();
this.emptyCondition = lock.newCondition();
}
public void produce(int val){
lock.lock();
try{
// left “ ”( , )
int left = val;
while(left>0){
// , “ ” 。
while(size>=capacity)
{
fullCondition.await();
}
// “ ”( )
// “ ”+“ ”>“ ”, “ ”=“ ”-“ ”。( )
// “ ”=“ ”
int inc = (size+left)>capacity ? (capacity-size) : left;
size += inc;
left -= inc;
System.out.println(Thread.currentThread().getName()+"want to produce" + val + "val-inc"+left + "actually produce "+ inc+ "now size"+size);
// “ ” 。
emptyCondition.signal();
}
} catch(InterruptedException e) {
}finally {
lock.unlock();
}
}
public void consume(int val){
lock.lock();
try{
// left “ ”( , , )
int left = val;
while (left > 0) {
// 0 , “ ” 。
while (size <= 0)
{
emptyCondition.await();
}
// “ ”( )
// “ ”