首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何“取消”CountDownLatch?

如何“取消”CountDownLatch?
EN

Stack Overflow用户
提问于 2012-05-05 02:02:00
回答 5查看 7.6K关注 0票数 18

我有多个使用者线程在使用await()的大小为1的CountDownLatch上等待。我有一个生产者线程,它在成功完成时调用countDown()

这在没有错误的情况下工作得很好。

但是,如果生产者检测到错误,我希望它能够向使用者线程发出错误信号。理想情况下,我可以让生产者调用像abortCountDown()这样的东西,让所有的消费者接收一个InterruptedException或其他一些异常。我不想调用countDown(),因为这需要我的所有使用者线程在调用await()之后执行额外的手动检查以确定是否成功。我更希望他们只收到一个异常,他们已经知道如何处理。

我知道在CountDownLatch中没有中止功能。有没有另一种同步原语可以让我轻松地创建一个支持中止倒计时的CountDownLatch

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-05-05 04:37:02

JB Nizet有一个很好的答案。我拿了他的,稍微打磨了一下。结果是CountDownLatch的一个名为AbortableCountDownLatch的子类,它向该类添加了一个"abort()“方法,该方法将导致等待锁存器的所有线程接收一个AbortException (InterruptedException的子类)。

此外,与JB的类不同,AbortableCountDownLatch将在中止时立即中止所有阻塞线程,而不是等待倒计时达到零(对于使用count>1的情况)。

代码语言:javascript
复制
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);
        }
    }
}
票数 17
EN

Stack Overflow用户

发布于 2012-05-05 02:08:34

在内部使用CountDownLatch将此行为封装在特定的更高级别的类中:

代码语言:javascript
复制
public class MyLatch {
    private CountDownLatch latch;
    private boolean aborted;
    ...

    // called by consumers
    public void await() throws AbortedException {
        latch.await();
        if (aborted) {
            throw new AbortedException();
        }
    }

    // called by producer
    public void abort() {
        this.aborted = true;
        latch.countDown();
    }

    // called by producer
    public void succeed() {
        latch.countDown();
    }
}
票数 13
EN

Stack Overflow用户

发布于 2012-05-05 02:10:52

您可以在CountDownLatch周围创建一个包装器,以提供取消服务员的能力。它将需要跟踪等待的线程,并在它们超时时释放它们,并记住锁存已被取消,以便将来对await的调用将立即中断。

代码语言:javascript
复制
public class CancellableCountDownLatch
{
    final CountDownLatch latch;
    final List<Thread> waiters;
    boolean cancelled = false;

    public CancellableCountDownLatch(int count) {
        latch = new CountDownLatch(count);
        waiters = new ArrayList<Thread>();
    }

    public void await() throws InterruptedException {
        try {
            addWaiter();
            latch.await();
        }
        finally {
            removeWaiter();
        }
    }

    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        try {
            addWaiter();
            return latch.await(timeout, unit);
        }
        finally {
            removeWaiter();
        }
    }

    private synchronized void addWaiter() throws InterruptedException {
        if (cancelled) {
            Thread.currentThread().interrupt();
            throw new InterruptedException("Latch has already been cancelled");
        }
        waiters.add(Thread.currentThread());
    }

    private synchronized void removeWaiter() {
        waiters.remove(Thread.currentThread());
    }

    public void countDown() {
        latch.countDown();
    }

    public synchronized void cancel() {
        if (!cancelled) {
            cancelled = true;
            for (Thread waiter : waiters) {
                waiter.interrupt();
            }
            waiters.clear();
        }
    }

    public long getCount() {
        return latch.getCount();
    }

    @Override
    public String toString() {
        return latch.toString();
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10453876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档