1. 程式人生 > 其它 >java.util.concurrent併發包之Condition

java.util.concurrent併發包之Condition

技術標籤:javajava

一、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 釋放鎖