java.util.concurrent併發包之Condition
阿新 • • 發佈:2021-02-19
一、Condition介面
Condition可以通俗的理解為條件佇列;
當一個執行緒在呼叫await方法以後,直到執行緒等待的某個條件為真的時候,待會被喚醒;
這種執行緒為簡單的等待/通知模式;
Condition必須和Lock配合使用,因為共享狀態變數的訪問發生在多執行緒環境下;
final Lock lock = new ReentrantLock();
final Condition ThreeConditon = lock.newCondition();
final Condition SixConditon = lock.newCondition( );
二、Condition介面中的方法
//當前執行緒在接到訊號或者被中斷之前一直處在等待狀態
void await() throws InterruptedException;
//當前執行緒在接到訊號之前一直處於等待狀態
void awaitUninterruptibly();
//當前執行緒在接到訊號、中斷或者在制定的時間之前一直在等待狀態。
//返回值long表示的剩餘時間。
//如果在nanosTimeout之前被喚醒,那麼返回值=nanosTimeout-消耗時間
//如果返回值小於0,可以認為它超時了
long awaitNanos(long nanosTimeout) throws InterruptedException;
//當前執行緒在接到訊號、中斷或者在制定的時間之前一直在等待狀態。
boolean await(long time, TimeUnit unit) throws InterruptedException;
//當前執行緒在接到訊號、中斷或者在制定的時間之前一直在等待狀態。
//如果沒有到指定時間,則返回true,否則返回false
boolean awaitUntil(Date deadline) throws InterruptedException;
//喚醒等待執行緒。
//該執行緒的從等待方法返回前必須獲得與Condition相關的lock
void signal();
//換新所有的等待執行緒
void signalAll ();
三、總結
呼叫await方法後,將當前執行緒加入到Condition等待佇列中;
當前佇列釋放lock,否則別的執行緒無法得到鎖,而造成死鎖;
自旋 while 掛起,不斷的檢查節點是否同步在佇列中;
如果是,則獲取lock;
否則掛起;
當執行緒被signal方法喚醒;
被喚醒的執行緒將從await方法中的while迴圈中退出來;
然後呼叫acquireQueue方法中競爭同步狀態;
四、栗子:兩個計數執行緒,同時啟動,執行緒A執行123,執行緒B執行456,然後執行緒A執行789,結束。
public class ConcurrentTest {
static class NumberWrapper{
public int value = 1;
}
public static void main(String... args) {
//初始化可重入鎖
//await和signal的Lock是同一個Lock
final Lock lock = new ReentrantLock();
//當螢幕上輸出3時,lock.newCondition()
final Condition reachThreeConditon = lock.newCondition();
//當螢幕上輸出6時,lock.newCondition()
final Condition reachSixConditon = lock.newCondition();
//NumberWrapper只是為了封裝一個數字,一邊可以數字物件共享,並可以設定為final
//注意這裡不要用Integer,因為Integer是不可比變物件
final NumberWrapper num = new NumberWrapper();
Thread threadA = new Thread(() -> {
//需要先獲得鎖
lock.lock();
System.out.println("ThreadA獲得Lock");
try{
System.out.println("ThreadA start write");
while (num.value <= 3) {
System.out.println(num.value);
num.value++;
}
//輸出到3的時候告訴B執行緒可以開始了
reachThreeConditon.signal();
} finally {
lock.unlock();
System.out.println("ThreadA 釋放鎖");
}
lock.lock();
System.out.println("ThreadA獲得Lock");
try{
//等待6輸出的條件
reachSixConditon.await();
System.out.println("ThreadA start write");
while (num.value <= 9) {
System.out.println(num.value);
num.value++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("ThreadA 釋放鎖");
}
});
Thread threadB = new Thread(() -> {
try {
lock.lock();
System.out.println("ThreadB獲得lock");
Thread.sleep(5000);
while (num.value <=3) {
//等待A執行緒輸出3完畢的訊號
reachThreeConditon.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("ThreadB釋放lock");
lock.unlock();
}
try {
lock.lock();
System.out.println("ThreadB獲得lock");
System.out.println("ThreadB start write");
while (num.value <= 6) {
System.out.println(num.value);
num.value++;
}
reachSixConditon.signal();
} finally {
System.out.println("ThreadB釋放lock");
lock.unlock();
}
});
threadB.start();
threadA.start();
}
}
執行結果:
ThreadB獲得lock
ThreadA獲得Lock
ThreadA start write
1
2
3
ThreadA 釋放鎖
ThreadA獲得Lock
ThreadB釋放lock
ThreadB獲得lock
ThreadB start write
4
5
6
ThreadB釋放lock
ThreadA start write
7
8
9
ThreadA 釋放鎖