Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.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 - Fatal编程技术网

Java 取消并完成定期任务时的回调

Java 取消并完成定期任务时的回调,java,Java,我有两个任务:第一个任务(工作)正在重复,第二个任务(清理)正在释放一些资源。重新发生的工作任务完成后,清理任务应仅运行一次,且不会再次运行 我的第一直觉是这样的: ScheduledExecutorService service = ...; ScheduledFuture<?> future = service.scheduleAtFixedRate(work, ...); // other stuff happens future.cancel(false); cleanu

我有两个任务:第一个任务(
工作
)正在重复,第二个任务(
清理
)正在释放一些资源。重新发生的
工作
任务完成后,
清理
任务应仅运行一次,且不会再次运行

我的第一直觉是这样的:

ScheduledExecutorService service = ...;
ScheduledFuture<?> future = service.scheduleAtFixedRate(work, ...);

// other stuff happens

future.cancel(false);
cleanup.run();
ScheduledExecutorService=。。。;
ScheduledFuture future=服务。scheduleAtFixedRate(工作,…);
//其他事情也会发生
未来。取消(假);
cleanup.run();
这里的问题是
cancel()
会立即返回。因此,如果
work
恰好正在运行,那么
cleanup
将重叠它

理想情况下,我会使用番石榴的
Futures.addCallback(ListenableFuture,FutureCallback-callback)
。(番石榴15号可能有)


同时,当
future
被取消并且
work
不再运行时,如何启动回调?

这就是我提出的解决方案。这似乎很简单,但我仍然认为有一个更常见和/或更优雅的解决方案。我真的很想在图书馆里看到一个像番石榴

首先,我创建了一个包装器,以便在我的Runnable上实现互斥:

private static final class SynchronizedRunnable implements Runnable {
    private final Object monitor;
    private final Runnable delegate;

    private SynchronizedRunnable(Object monitor, Runnable delegate) {
        this.monitor = monitor;
        this.delegate = delegate;
    }

    @Override
    public void run() {
        synchronized (monitor) {
            delegate.run();
        }
    }
}
然后,我创建一个包装器,在成功调用
cancel
时触发回调:

private static final class FutureWithCancelCallback<V> extends ForwardingFuture.SimpleForwardingFuture<V> {

    private final Runnable callback;

    private FutureWithCancelCallback(Future<V> delegate, Runnable callback) {
        super(delegate);
        this.callback = callback;
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
            boolean cancelled = super.cancel(mayInterruptIfRunning);
            if (cancelled) {
                callback.run();
            }
            return cancelled;
    }
}
私有静态最终类FutureWithCancelCallback扩展ForwardingFuture.SimpleForwardingFuture{
私有最终可运行回调;
private FutureWithCancelCallback(未来委托,可运行回调){
超级(代表);
this.callback=回调;
}
@凌驾
公共布尔值取消(布尔值可能中断刷新){
布尔取消=超级。取消(可能中断frunning);
如果(取消){
callback.run();
}
退货取消;
}
}
然后,我用自己的方法将其全部滚动:

private Future<?> scheduleWithFixedDelayAndCallback(ScheduledExecutorService service, Runnable work, long initialDelay, long delay, TimeUnit unit, Runnable cleanup) {

    Object monitor = new Object();

    Runnable monitoredWork = new SynchronizedRunnable(monitor, work);

    Runnable monitoredCleanup = new SynchronizedRunnable(monitor, cleanup);

    Future<?> rawFuture = service.scheduleAtFixedRate(monitoredWork, initialDelay, delay, unit);

    Future<?> wrappedFuture = new FutureWithCancelCallback(rawFuture, monitoredCleanup);

    return wrappedFuture;
}
private Future schedule with fixeddelayandcallback(ScheduledExecutorService服务、可运行工作、长初始延迟、长延迟、时间单位、可运行清理){
对象监视器=新对象();
Runnable monitoredWork=新的SynchronizedRunnable(监视器,工作);
Runnable monitoredCleanup=新的SynchronizedRunnable(监视器,清理);
Future rawFuture=service.scheduleAtFixedRate(监视工作、初始延迟、延迟、单位);
Future wrappedFuture=带有CancelCallback的新Future(rawFuture,monitoredCleanup);
回归包装未来;
}
你为什么不这样做

// other stuff happens

future.cancel(false);
service.shutdown();
service.awaitTermination(1, TimeUnit.DAYS);
cleanup.run();

这将告诉您的executor服务关闭,从而允许您等待可能正在运行的
工作完成。

然后我将再次尝试。您可以增强该命令,也可以包装已执行的
Runnable
/
Callable
。看看这个:

public static class RunnableWrapper implements Runnable {

    private final Runnable original;
    private final Lock lock = new ReentrantLock();

    public RunnableWrapper(Runnable original) {
        this.original = original;
    }

    public void run() {
        lock.lock();
        try {
            this.original.run();
        } finally {
            lock.unlock();
        }
    }

    public void awaitTermination() {
        lock.lock();
        try {
        } finally {
            lock.unlock();
        }
    }

}
因此,您可以将代码更改为

ScheduledExecutorService service = ...;
RunnableWrapper wrapper = new RunnableWrapper(work);
ScheduledFuture<?> future = service.scheduleAtFixedRate(wrapper, ...);

// other stuff happens

future.cancel(false);
wrapper.awaitTermination();
cleanup.run();
ScheduledExecutorService=。。。;
RunnableRapper包装器=新的RunnableRapper(工作);
ScheduledFuture future=service.scheduleAtFixedRate(包装器,…);
//其他事情也会发生
未来。取消(假);
waitivetermination();
cleanup.run();

调用
cancel
后,要么
work
不再运行,要么
等待终止()
立即返回,要么它正在运行,等待终止()
阻塞,直到完成。

我不想取消executor服务中的所有任务。。。就是我预定的那个。事实上,ScheduledExecutorService是提供给我的,我不知道还有谁在向它提交任务。哦,这太不幸了。。。这就排除了扩展ScheduledExecutorService的可能性,因为在这里您可以有更多的选择。您的
工作
实例如何?那在你手里吗?是的,工作和清理任务/可运行程序是我的。我想将线程/执行器问题与工作/清理中的业务逻辑分开。。。但我很乐意让这些类从某个任务继承,或者我可以将它们封装在其他可运行/可调用的类中你的解决办法和我的差不多。我之所以接受我的解决方案,只是因为从客户的角度来看,这更像是“放火而忘记”。对于我的特定场景,这是一个很好的属性。