Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I "cancel" a CountDownLatch?

I have multiple consumer threads waiting on a CountDownLatch of size 1 using await(). I have a single producer thread that calls countDown() when it successfully finishes.

This works great when there are no errors.

However, if the producer detects an error, I would like for it to be able to signal the error to the consumer threads. Ideally I could have the producer call something like abortCountDown() and have all of the consumers receive an InterruptedException or some other exception. I don't want to call countDown(), because this requires all of my consumer threads to then do an additional manual check for success after their call to await(). I'd rather they just receive an exception, which they already know how to handle.

I know that an abort facility is not available in CountDownLatch. Is there another synchronization primitive that I can easily adapt to effectively create a CountDownLatch that supports aborting the countdown?

like image 240
emmby Avatar asked May 04 '12 18:05

emmby


People also ask

How do I reset my CountDownLatch?

Every time when CountDownLatch. countDown() is called, the value of count will decrease by 1 until the value becomes 0. One thing to be noted is that the value of count cannot be reset. i.e, when count becomes 0, the CountDownLatch will not work anymore, the call to await() method will return immediately.

What is CyclicBarrier and CountDownLatch?

As stated in the definitions, CyclicBarrier allows a number of threads to wait on each other, whereas CountDownLatch allows one or more threads to wait for a number of tasks to complete. In short, CyclicBarrier maintains a count of threads whereas CountDownLatch maintains a count of tasks.

What is latch await?

await() Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted. boolean. await(long timeout, TimeUnit unit) Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted, or the specified waiting time elapses.


1 Answers

JB Nizet had a great answer. I took his and polished it a little bit. The result is a subclass of CountDownLatch called AbortableCountDownLatch, which adds an "abort()" method to the class that will cause all threads waiting on the latch to receive an AbortException (a subclass of InterruptedException).

Also, unlike JB's class, the AbortableCountDownLatch will abort all blocking threads immediately on an abort, rather than waiting for the countdown to reach zero (for situations where you use a count>1).

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class AbortableCountDownLatch extends CountDownLatch {
    protected boolean aborted = false;

    public AbortableCountDownLatch(int count) {
        super(count);
    }


   /**
     * Unblocks all threads waiting on this latch and cause them to receive an
     * AbortedException.  If the latch has already counted all the way down,
     * this method does nothing.
     */
    public void abort() {
        if( getCount()==0 )
            return;

        this.aborted = true;
        while(getCount()>0)
            countDown();
    }


    @Override
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        final boolean rtrn = super.await(timeout,unit);
        if (aborted)
            throw new AbortedException();
        return rtrn;
    }

    @Override
    public void await() throws InterruptedException {
        super.await();
        if (aborted)
            throw new AbortedException();
    }


    public static class AbortedException extends InterruptedException {
        public AbortedException() {
        }

        public AbortedException(String detailMessage) {
            super(detailMessage);
        }
    }
}
like image 163
emmby Avatar answered Sep 23 '22 05:09

emmby