同時メカニズムに基づいて生産者-消費者モデルを実現する


前回はjdkの元の同期メカニズムを用いて生産者-消費者モデルを実現したが、今回はjdk 1に変更した.5で提供される関連する同時クラスは、生産者-消費者モデルを実現する.

まず2つのクラス(インタフェース)について説明します。

  • ReentrantLockクラス
  • の役割はsynchronizedコードブロックとあまり差がなく、反発を実現するために使用されます.もちろん、両者には違いがあります.

  • Conditionインタフェース
  • それはawait()、signal()、signalAll()などの方法を提供し、Objectクラスのwait()、signal()とsignalAll()の方法と同じである.インタフェースであるため、newはできません.ReentrantLockクラスのnewConditionメソッドを使用して、ReentrantLockオブジェクトに関連付けられたConditionオブジェクト(実際にはConditionObjectクラスオブジェクト)を取得する必要があります.


  • 同様に、Conditionのawait()、signal()、signalAll()は、呼び出すには対応するReentrantLockロックを取得する必要があります.
    ここでは、同じReentrantLockオブジェクトを使用してnewConditionを複数回呼び出して複数のConditionオブジェクトを取得し、より複雑な同期関係を実現することができますが、Objectクラスを使用するのは1つのConditionオブジェクトのみに相当します.もちろん、異なるConditionオブジェクトの中で、待機と起動は対応しなければならない.例えば、newConditionメソッドを2回呼び出し、2つのConditionオブジェクトcondition 1とcondition 2を得た.もし私がスレッドAでcondition 1を呼び出したら.await()は、スレッドBがcondition 2を呼び出す.signal()では、スレッドAは必ず起動されず、condition 1を呼び出すべきである.Signal()スレッドAが呼び覚まされる可能性がありますが、なぜ可能とは限らないのでしょうか.なぜならsignal()はObjectクラスのnotify()と同じであり、システムは待機セットのスレッドをランダムに起動し、私たちのスレッドAが選択されるとは限らないからです.

    生産者-消費者モデル(ブロックキュー):

    public class ProducerConsumerCondition {
    
        private int bufSize;
        private int[] buf;
        private int currentSize;
    
        private ReentrantLock mainLock = new ReentrantLock();
    
        private Condition putCondition = mainLock.newCondition();
        private Condition getCondition = mainLock.newCondition();
    
        public ProducerConsumerCondition() {
            this(10);
        }
    
        public ProducerConsumerCondition(int bufSize) throws IllegalArgumentException{
            this.bufSize = bufSize;
            if(bufSize < 0) {
                throw new IllegalArgumentException("bufSize can't less zero");
            }
            buf = new int[bufSize];
        }
    
        public void put(int v) throws InterruptedException{
            mainLock.lock();
            try {
                while(currentSize >= bufSize) {
                    putCondition.await();
                }
                if(currentSize < bufSize) {
                    buf[currentSize++] = v;
                    getCondition.signal();
                }
            } catch(InterruptedException e) {
                 throw e;
            } finally {
                mainLock.unlock();
            }
        }
    
        public int get() throws InterruptedException{
            mainLock.lock();
            try {
                while(currentSize == 0) {
                    getCondition.await();
                }
                if(currentSize > 0) {
                    int temp = buf[currentSize - 1];
                    currentSize--;
                    putCondition.signal();
                    return temp;
                }
            } catch(InterruptedException e) {
                throw e;
            } finally {
                mainLock.unlock();
            }
        }
    
        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("[");
            sb.append("queue's length=" + currentSize);
            sb.append(" ");
            for(int i = 0; i < currentSize - 1; i++) {
                sb.append(buf[i] + ",");
            }
            if(currentSize > 0) {
                sb.append(buf[currentSize - 1]);
            }
            sb.append("]");
            return sb.toString();
        }
    }
    

    説明


    1.コードからReentrantLockを使用する欠点の一つは、lockが完了するたびにfinallyブロックでunLockを実行しなければならないということです.これは私たちがいつでも覚えているわけではありません.
    転載は原文の住所を明記してください.http://blog.csdn.net/u012619640/article/details/48090939