[concurrency-interest] ReadWriteLocks and Conditions

Peter Veentjer alarmnummer at gmail.com
Tue Feb 6 03:55:36 EST 2007


I don't see how a Future would fit in, maybe you could elaborate on this?

I have decided to drop the version with the ReadWriteLock completely.
One of the problems was with the condition, and another problem is
that a reference can't be taken back by a different thread than took
it (a lock has to be released by the same thread as locked it).

In the bus to my work I created a different implementation:

public class NewStrictLendeableReference<E> implements LendableReference<E> {

    public static Lock newDefaultMainLock(){
        return new ReentrantLock();
    }

    private final Lock mainLock;
    private final Condition refAvailableCondition;
    private final Condition noTakersCondition;
    private volatile long lendCount = 0;
    private volatile E ref;

    public NewStrictLendeableReference(){
        this(newDefaultMainLock(),null);
    }

    public NewStrictLendeableReference(E ref){
        this(newDefaultMainLock(),ref);
    }

    public NewStrictLendeableReference(boolean fair, E ref){
        this(new ReentrantLock(fair),ref);
    }

    public NewStrictLendeableReference(Lock mainLock, E ref) {
        if (mainLock == null) throw new NullPointerException();
        this.ref = ref;
        this.mainLock = mainLock;
        refAvailableCondition = mainLock.newCondition();
        noTakersCondition = mainLock.newCondition();
    }

    public Lock getMainLock() {
        return mainLock;
    }

    public Condition getRefAvailableCondition() {
        return refAvailableCondition;
    }

    public Condition getNoTakersCondition() {
        return noTakersCondition;
    }

    public long getLendCount() {
        return lendCount;
    }

    public E take() throws InterruptedException {
        mainLock.lockInterruptibly();

        try {
            while (ref == null)
                refAvailableCondition.await();

            lendCount++;
            return ref;
        } finally {
            mainLock.unlock();
        }
    }

    public E tryTake(long timeout, TimeUnit unit) throws
InterruptedException, TimeoutException {
        if (unit == null) throw new NullPointerException();

        long timeoutNs = toUsableNanos(timeout,unit);
        mainLock.lockInterruptibly();
        try{
            while(ref == null)
                timeoutNs = awaitAndThrow(refAvailableCondition,timeoutNs);

            lendCount++;
            return ref;
        }finally{
            mainLock.unlock();
        }
    }

    public void takeBack(E ref) {
        if (ref == null) throw new NullPointerException();

        mainLock.lock();
        try {
            if (!ref.equals(this.ref))
                throw new IncorrectReferenceTakenBackException();

            if (lendCount == 0)
                throw new RuntimeException();

            lendCount--;
            if (lendCount == 0)
                noTakersCondition.signalAll();
        } finally {
            mainLock.unlock();
        }
    }

    public E put(E newRef) throws InterruptedException {
        mainLock.lockInterruptibly();
        try {
            while (lendCount > 0)
                noTakersCondition.await();

            return updateReference(newRef);
        } finally {
            mainLock.unlock();
        }
    }

    private E updateReference(E newRef) {
        E oldRef = ref;
        this.ref = newRef;
        if (ref != null)
            refAvailableCondition.signalAll();
        return oldRef;
    }

    public E tryPut(E newRef, long timeout, TimeUnit unit) throws
InterruptedException, TimeoutException {
        if (unit == null) throw new NullPointerException();

        long timeoutNs = toUsableNanos(timeout,unit);

        mainLock.lockInterruptibly();
        try {
            while (lendCount > 0)
                timeoutNs = awaitAndThrow(noTakersCondition,timeoutNs);

            return updateReference(newRef);
        } finally {
            mainLock.unlock();
        }
    }

    public E peek() {
        return ref;
    }
}


On 2/5/07, Gregg Wonderly <gergg at cox.net> wrote:
> Peter Veentjer wrote:
> > I'm working on a structure called the LendeableReference. This
> > structure makes it possible to lend a reference to multiple threads
> > (values are taken from the LendableReference) and after a thread is
> > done with the reference, it takes it back so that a new reference can
> > be set. If no reference is available, taking threads block until a
> > reference is available.
>
> It seems to me that Future would be a better match for this.  Is there something
> about Future that is not a good match?
>
> Gregg Wonderly
>


More information about the Concurrency-interest mailing list