Java同時プログラミング実戦--明示的なConditionオブジェクト


ロックは一般化された内蔵ロックであり、Conditionも一般化された内蔵条件キューである.
public interface Condition {
    void await() throws InterruptedException;
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    //  nanosTimeout       ,     ;    ,           0   ,
    //                   ,       nanosTimeout   ,
    //                           ,       ,            nanosTimeout
    //(             nanosTimeout,         ,    await  )
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    //     :          ,condition.await       InterruptedException  。
    //                     (      。      ),
    //      condition.awaitUninterruptibly     await。
    void awaitUninterruptibly();
    boolean awaitUntil(Date deadline) throws InterruptedException;

    void signal();
    void signalAll();
}

内蔵された条件キューにはいくつかの欠陥があります.各組み込みロックには、関連する条件キューが1つしかありません.したがって、BoundedBufferのような種類では、次のようになります.
@ThreadSafe
public abstract class BaseBoundedBuffer  {
    @GuardedBy("this") private final V[] buf;
    @GuardedBy("this") private int tail;
    @GuardedBy("this") private int head;
    @GuardedBy("this") private int count;

    protected BaseBoundedBuffer(int capacity) {
        this.buf = (V[]) new Object[capacity];
    }

    protected synchronized final void doPut(V v) {
        buf[tail] = v;
        if (++tail == buf.length)
            tail = 0;
        ++count;
    }

    protected synchronized final V doTake() {
        V v = buf[head];
        buf[head] = null;
        if (++head == buf.length)
            head = 0;
        --count;
        return v;
    }

    public synchronized final boolean isFull() {
        return count == buf.length;
    }

    public synchronized final boolean isEmpty() {
        return count == 0;
    }
}

@ThreadSafe
    public class BoundedBuffer  extends BaseBoundedBuffer {
    // CONDITION PREDICATE: not-full (!isFull())
    // CONDITION PREDICATE: not-empty (!isEmpty())
    public BoundedBuffer() {
        this(100);
    }

    public BoundedBuffer(int size) {
        super(size);
    }

    // BLOCKS-UNTIL: not-full
    public synchronized void put(V v) throws InterruptedException {
        while (isFull())
            wait();
        doPut(v);
        notifyAll();
    }

    // BLOCKS-UNTIL: not-empty
    public synchronized V take() throws InterruptedException {
        while (isEmpty())
            wait();
        V v = doTake();
        notifyAll();
        return v;
    }

    // BLOCKS-UNTIL: not-full
    // Alternate form of put() using conditional notification
    public synchronized void alternatePut(V v) throws InterruptedException {
        while (isFull())
            wait();
        boolean wasEmpty = isEmpty();
        doPut(v);
        if (wasEmpty)
            notifyAll();
    }
}

複数のスレッドは、同じ条件キュー上で異なる条件述語を待機し、最も一般的なロックモードで条件キューオブジェクトを開示することができる.これらの要因は、notifyAllを呼び出すときにすべての待機スレッドが同じタイプである必要を満たすことができません.複数の条件述語を持つ同時オブジェクトを作成する場合や、条件キューの可視性以外の制御権を取得する場合は、組み込みロックや条件キューではなく明示的なロックとConditionを使用すると、より柔軟な選択ができます.
条件キューと内蔵ロックが関連付けられているように、条件キューが関連付けられています.Conditionを作成するには、関連するLockでLock.newConditionメソッドを呼び出すことができます.ロックが内蔵ロックよりも豊富な機能を提供しているように、Conditionは内蔵条件キューよりも豊富な機能を提供しています.各ロックに複数の待機が存在し、条件待機が中断可能または中断不可能であり、時間ベースの待機、および公平または非公平なキュー操作があります.
   は、内蔵条件キューとは異なり、ロックごとに任意の数のConditionオブジェクトを持つことができる.Conditionオブジェクトは関連するLockオブジェクトの公平性を継承し、公平なロックの場合、スレッドはFIFO順にCondition.awaitから解放されます.
特に注意:Conditionオブジェクトではwait,notify,notifyAllメソッドに対応するものはawait,signal,signalAllである.しかし、ConditionはObjectを拡張しているので、waitメソッドとnotifyメソッドも含まれています.awaitとsignalの正しいバージョンが使用されていることを確認してください.
package net.jcip.examples;

import java.util.concurrent.locks.*;

import net.jcip.annotations.*;

/**
 * ConditionBoundedBuffer
 * 
 * Bounded buffer using explicit condition variables
 *
 * @author Brian Goetz and Tim Peierls
 */

@ThreadSafe
public class ConditionBoundedBuffer  {
    protected final Lock lock = new ReentrantLock();
    // CONDITION PREDICATE: notFull (count < items.length)
    private final Condition notFull = lock.newCondition();
    // CONDITION PREDICATE: notEmpty (count > 0)
    private final Condition notEmpty = lock.newCondition();
    private static final int BUFFER_SIZE = 100;
    @GuardedBy("lock") private final T[] items = (T[]) new Object[BUFFER_SIZE];
    @GuardedBy("lock") private int tail, head, count;

    // BLOCKS-UNTIL: notFull
    public void put(T x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await();
            items[tail] = x;
            if (++tail == items.length)
                tail = 0;
            ++count;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    // BLOCKS-UNTIL: notEmpty
    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await();
            T x = items[head];
            items[head] = null;
            if (++head == items.length)
                head = 0;
            --count;
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}

ConditionBoundedBufferはBoundedBufferと同じ動作をしていますが、条件キューの使用については理解しやすいです.複数のConditionを使用するクラスを分析するときは、単一の内部キューを使用して複数の条件述語を追加するクラスを分析するよりも簡単です.**2つの条件述語を2つの待機スレッドセットに分割して配置することで、Conditionは単一の通知の要件をより容易に満たすことができます.**SignalはsignalAllよりも効率的であり、キャッシュ操作のたびに発生するコンテキスト切替とロック要求の回数を大幅に低減することができる.
   は、内蔵ロックや条件キューと同様に、明示的なロックやConditionを使用する場合も、ロック、条件述語、条件変数の3元関係を満たす必要があります.条件述語に含まれる変数はロックによって保護され、条件述語をチェックしてawaitとsignalを呼び出すときはロックオブジェクトを持つ必要があります.
  明示的なConditionと組み込み条件キューの間で選択する場合、ReentrantLockとsynchronizedの間で選択するのと同じです.公平なキュー操作を使用するか、各ロックに複数の待機スレッドセットを対応させるなどの高度な機能が必要な場合は、組み込み条件キューではなくConditionを優先的に使用する必要があります.(ReentrantLockの高度な機能が必要で、すでに使用されている場合は、すでに選択されています.)
lock:指定した開始位置と終了位置を表示する必要があります.ロックとしてReentrantLockクラスを使用するのが一般的で、複数のスレッドで1つのReentrantLockクラスをオブジェクトとして使用する必要があります.
Java同時プログラミング実戦pdf及びケースソースダウンロード:http://download.csdn.net/detail/xunzaosiyecao/9851028
作者:jiankunking出典:http://blog.csdn.net/jiankunking