Conditionインタフェースの概要

4089 ワード

このブログシリーズは、同時プログラミングを学習する際の記録のまとめです.文章が多くて、書く時間もバラバラなので、ディレクトリシール(転送ドア)を整理して、調べやすいです.
同時プログラミングシリーズブログ転送ゲート

インタフェースの概要


Conditionは、Obejct類のwait()notify()notifyAll()の方法の代替品として、Lockと併用して使用することができる.スレッドがconditionオブジェクトのawaitメソッドを実行すると、現在のスレッドはすぐにロックを解除し、オブジェクトの待機領域に入り、他のスレッドの起動または中断を待つ.
JUCは、Conditonオブジェクトを実装する際に、AQSフレームワークを実装することによって、Condition待ちキューを実装しています.これは、AQSフレームワークについて後述する際に詳しく説明しますが、現在はConditionがどのように使用されているかを知るだけです.

インタフェース定義

public interface Condition {

    void await() throws InterruptedException;

    long awaitNanos(long nanosTimeout) throws InterruptedException;
    
    boolean await(long time, TimeUnit unit) throws InterruptedException;

    boolean awaitUntil(Date deadline) throws InterruptedException;

    void signal();

    void signalAll();
}

使用例


wait-notifyモードの典型的な応用は、生産者-消費者モードを実現することができることである.私が卒業した年にアリババのキャンパスで募集した筆記試験の問題が印象的でした.
1つのリンゴ箱があり、10人がこの箱にランダムにリンゴを1つずつ入れ、10人がランダムにこの箱からランダムにリンゴを1つ持っていくと同時に、箱の中のリンゴの総数を50個以上満たす必要がある.上のシーンをコードで実装してください(コンカレントコレクションフレームワークは使用できません)
この問題はwait-notifyモードを用いてよく解決できる.以下にConditionモードを用いて記す.
public class AppleBoxConditon {

    private int appleCount;
    private static Lock lock = new ReentrantLock();
    private static Condition fullCondition = lock.newCondition();
    private static Condition emptyCondition = lock.newCondition();

    public void putApple() {
        lock.lock();
        try {
            while (appleCount >= 10) {
                try {
                    fullCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            appleCount++;
            System.out.println(" , :" + appleCount);
            emptyCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }


    public void takeApple() {
        lock.lock();
        try{
            while (appleCount <= 0) {
                try {
                    emptyCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            appleCount--;
            System.out.println(" , :" + appleCount);
            fullCondition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    private static class AppleTaker implements Runnable {

        private AppleBoxConditon appleBox;

        public AppleTaker(AppleBoxConditon appleBox) {
            this.appleBox = appleBox;
        }

        @Override
        public void run() {
            while (true) {
                appleBox.takeApple();
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private static class ApplePutter implements Runnable {

        private AppleBoxConditon appleBox;

        public ApplePutter(AppleBoxConditon appleBox) {
            this.appleBox = appleBox;
        }

        @Override
        public void run() {
            while (true) {
                appleBox.putApple();
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public static void main(String[] args) {
        AppleBoxConditon appleBox = new AppleBoxConditon();


        for (int i = 0; i < 20; i++) {
            Thread t = new Thread(new AppleBoxConditon.ApplePutter(appleBox));
            t.setName("ApplePutter:"+i);
            t.start();
        }

        for (int i = 0; i < 20; i++) {
            Thread t = new Thread(new AppleBoxConditon.AppleTaker(appleBox));
            t.setName("AppleTaker:"+i);
            t.start();
        }

    }

}