2 回答

TA貢獻(xiàn)1772條經(jīng)驗(yàn) 獲得超8個(gè)贊
您可以通過(guò)以下方式實(shí)現(xiàn)您的目標(biāo):
A
Set<Runnable>
跟蹤Runnable
線程池已開(kāi)始執(zhí)行的 s。A
Map<ScheduledFuture<?>, Runnable>
將 a 映射ScheduledFuture<?>
到其各自的Runnable
.安排任務(wù)后,您應(yīng)立即將
ScheduledFuture
及其各自添加Runnable
到Map
.如果在調(diào)度任務(wù)本身的情況下以原子方式執(zhí)行插入
Map
,那么您可以避免即使在取消之后也ScheduledFuture
從未添加到的邊緣情況。Map
我建議將您更改ScheduledExecutorService
為 a ScheduledThreadPoolExecutor
,這將允許您覆蓋其beforeExecute(Thread, Runnable)
方法;這個(gè)方法在任務(wù)被池運(yùn)行之前立即調(diào)用,在它已經(jīng)被分配了一個(gè)將執(zhí)行任務(wù)的線程之后。
覆蓋此方法時(shí),您可以Runnable
將Set<Runnable>
.
然后,當(dāng) aScheduledFuture
被取消時(shí),您可以調(diào)用set.contains(map.get(future))
,它會(huì)告訴您Runnable
(ScheduledFuture
映射到的)是否已執(zhí)行。
請(qǐng)注意,您的Set<Runnable>
和Map<ScheduledFuture<?>, Runnable>
實(shí)現(xiàn)可能必須是線程安全的,以避免可能的競(jìng)爭(zhēng)條件。

TA貢獻(xiàn)1784條經(jīng)驗(yàn) 獲得超9個(gè)贊
我最終為這個(gè)問(wèn)題寫(xiě)了這樣的東西。源代碼和一些單元測(cè)試可以在https://github.com/nuzayats/cancellabletaskexecutor找到
public class CancellableTaskExecutor {
private final ScheduledExecutorService es;
private final Logger log;
/**
* For a unit test to replicate a particular timing
*/
private final Runnable hookBetweenCancels;
public CancellableTaskExecutor(ScheduledExecutorService es, Logger log) {
this(es, log, () -> {
// nop
});
}
// For unit tests
CancellableTaskExecutor(ScheduledExecutorService es, Logger log, Runnable hookBetweenCancels) {
this.es = es;
this.log = log;
this.hookBetweenCancels = hookBetweenCancels;
}
public Execution schedule(Runnable task, long delay, TimeUnit unit) {
CancellableRunnable runnable = new CancellableRunnable(task);
ScheduledFuture<?> future = es.schedule(runnable, delay, unit);
return new Execution(future, runnable);
}
public class Execution {
private final ScheduledFuture<?> future;
private final CancellableRunnable runnable;
private Execution(ScheduledFuture<?> future, CancellableRunnable runnable) {
this.future = future;
this.runnable = runnable;
}
/**
* @return true when the task has been successfully cancelled and it's guaranteed that
* the task won't get executed. otherwise false
*/
public boolean cancel() {
boolean cancelled = runnable.cancel();
hookBetweenCancels.run();
// the return value of this call is unreliable; see https://stackoverflow.com/q/55922874/3591946
future.cancel(false);
return cancelled;
}
}
private class CancellableRunnable implements Runnable {
private final AtomicBoolean cancelledOrStarted = new AtomicBoolean();
private final Runnable task;
private CancellableRunnable(Runnable task) {
this.task = task;
}
@Override
public void run() {
if (!cancelledOrStarted.compareAndSet(false, true)) {
return; // cancelled, forget about the task
}
try {
task.run();
} catch (Throwable e) {
log.log(Level.WARNING, "Uncaught Exception", e);
}
}
boolean cancel() {
return cancelledOrStarted.compareAndSet(false, true);
}
}
}
添加回答
舉報(bào)