Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java “我该怎么做?”;取消“;倒计时?_Java_Concurrency_Java.util.concurrent - Fatal编程技术网

Java “我该怎么做?”;取消“;倒计时?

Java “我该怎么做?”;取消“;倒计时?,java,concurrency,java.util.concurrent,Java,Concurrency,Java.util.concurrent,我有多个使用者线程正在使用wait()等待大小为1的CountDownLatch。我有一个生产者线程,当它成功完成时调用countDown() 这在没有错误的情况下非常有效 但是,如果生产者检测到错误,我希望它能够向使用者线程发送错误信号。理想情况下,我可以让生产者调用类似于abortCountDown()的东西,并让所有消费者接收到中断异常或其他异常。我不想调用countDown(),因为这需要我的所有使用者线程在调用wait()后,再进行一次额外的手动检查,以确定是否成功。我宁愿他们只是收到

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

这在没有错误的情况下非常有效

但是,如果生产者检测到错误,我希望它能够向使用者线程发送错误信号。理想情况下,我可以让生产者调用类似于
abortCountDown()
的东西,并让所有消费者接收到中断异常或其他异常。我不想调用
countDown()
,因为这需要我的所有使用者线程在调用
wait()
后,再进行一次额外的手动检查,以确定是否成功。我宁愿他们只是收到一个异常,他们已经知道如何处理


我知道,
CountDownLatch
中没有中止功能。是否还有另一个我可以轻松适应的同步原语,以有效地创建支持中止倒计时的
倒计时闩锁

在内部使用倒计时闩锁,将此行为封装在特定的高级类中:

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();
    }
}

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

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();
    }
}
public类cancelableCountdownlatch
{
最终倒计时闩锁;
最后名单服务员;
布尔值=假;
公共可取消CountDownLatch(整数计数){
闩锁=新的倒计时闩锁(计数);
waiters=newarraylist();
}
public void await()引发InterruptedException{
试一试{
addwater();
satch.wait();
}
最后{
移除服务员();
}
}
公共布尔等待(长超时,时间单位)抛出InterruptedException{
试一试{
addwater();
返回闩锁。等待(超时,单位);
}
最后{
移除服务员();
}
}
private synchronized void addwater()引发InterruptedException{
如果(取消){
Thread.currentThread().interrupt();
抛出新的InterruptedException(“闩锁已被取消”);
}
add(Thread.currentThread());
}
私有同步的void removeWayer(){
移除(Thread.currentThread());
}
公共空间倒计时(){
倒计时();
}
公共同步作废取消(){
如果(!取消){
取消=真;
供(服务员:服务员){
服务员,打断一下;
}
服务员:明白;
}
}
公共长getCount(){
返回闩锁。getCount();
}
@凌驾
公共字符串toString(){
返回闩锁.toString();
}
}

您可以使用允许访问其受保护方法的
可重入锁
将自己的
倒计时锁
推出

例如:

public class FailableCountDownLatch {
    private static class ConditionReentrantLock extends ReentrantLock {
        private static final long serialVersionUID = 2974195457854549498L;

        @Override
        public Collection<Thread> getWaitingThreads(Condition c) {
            return super.getWaitingThreads(c);
        }
    }

    private final ConditionReentrantLock lock = new ConditionReentrantLock();
    private final Condition countIsZero = lock.newCondition();
    private long count;

    public FailableCountDownLatch(long count) {
        this.count = count;
    }

    public void await() throws InterruptedException {
        lock.lock();
        try {
            if (getCount() > 0) {
                countIsZero.await();
            }
        } finally {
            lock.unlock();
        }
    }

    public boolean await(long time, TimeUnit unit) throws InterruptedException {
        lock.lock();
        try {
            if (getCount() > 0) {
                return countIsZero.await(time, unit);
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

    public long getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }

    public void countDown() {
        lock.lock();
        try {
            if (count > 0) {
                count--;

                if (count == 0) {
                    countIsZero.signalAll();
                }
            }
        } finally {
            lock.unlock();
        }
    }

    public void abortCountDown() {
        lock.lock();
        try {
            for (Thread t : lock.getWaitingThreads(countIsZero)) {
                t.interrupt();
            }
        } finally {
            lock.unlock();
        }
    }
}
公共类故障倒计时闩锁{
私有静态类ConditionReentrantLock扩展了ReentrantLock{
私有静态最终长serialVersionUID=29741954578549498L;
@凌驾
公共集合getWaitingThreads(条件c){
返回super.getWaitingThreads(c);
}
}
private final ConditionReentrantLock=new ConditionReentrantLock();
私有最终条件countIsZero=lock.newCondition();
私人长计数;
公共FailableCountDownLatch(长计数){
this.count=计数;
}
public void await()引发InterruptedException{
lock.lock();
试一试{
如果(getCount()>0){
countIsZero.wait();
}
}最后{
lock.unlock();
}
}
公共布尔等待(长时间,时间单位)抛出InterruptedException{
lock.lock();
试一试{
如果(getCount()>0){
返回计数为零。等待(时间,单位);
}
}最后{
lock.unlock();
}
返回true;
}
公共长getCount(){
lock.lock();
试一试{
返回计数;
}最后{
lock.unlock();
}
}
公共空间倒计时(){
lock.lock();
试一试{
如果(计数>0){
计数--;
如果(计数=0){
countIsZero.signalAll();
}
}
}最后{
lock.unlock();
}
}
公共无效中止计数(){
lock.lock();
试一试{
for(线程t:lock.getWaitingThreads(countIsZero)){
t、 中断();
}
}最后{
lock.unlock();
}
}
}

您可能希望更改该类,以便在取消该类后,对
wait
的新调用抛出
InterruptedException
。如果您需要该功能,您甚至可以让该类扩展CountDownLatch。

。我拿了他的,擦了擦。结果是CountDownLatch的一个子类AbortableCountDownLatch,它向该类添加了一个“abort()”方法,该方法将导致等待该闩锁的所有线程接收AbortException(InterruptedException的子类)

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


由于Java8,您可以使用CompletableFuture来实现这一点。一个或多个线程可以调用blocking get()方法:

CompletableFuture cf=new Comple
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);
        }
    }
}
CompletableFuture<Void> cf = new CompletableFuture<>();
try {
  cf.get();
} catch (ExecutionException e) {
  //act on error
}