以下是我的内容......我有一个任务列表,每个任务都会自己提交ExecutorService
。我希望每个任务在开始执行后的时间限制为x MS。我已经看到了Time Limit on Individual Threads发布的解决方案,但这会在提交任务时开始设置时间限制。
我认为一个解决方案是对Time Limit on Individual Threads的公认解决方案的扩展。这会将Callable
包装在另一个Callable
中,一旦启动就将取消任务放在计划执行程序上。这将涉及以非平凡的方式将Callable
映射到Future
,所以我想我会发布以查看是否有人知道现有的解决方案(代码重用是一件很棒的事情,全部)。
感谢。
作为一个FYI,Time Limit on Individual Threads发布的解决方案如下。这再次取消了提交时间,而不是开始时间:
ExecutorService service = Executors.newFixedThreadPool(N);
ScheduledExecutorService canceller = Executors.newSingleThreadScheduledExecutor();
public <T> Future<T> executeTask(Callable<T> c, long timeoutMS){
final Future<T> future = service.submit(c);
canceller.schedule(new Callable<Void>(){
public Void call(){
future.cancel(true);
return null;
}
}, timeoutMS, TimeUnit.MILLI_SECONDS);
return future;
}
答案 0 :(得分:2)
看看这是否适合你。
很抱歉,如果代码很乱,但它只是为了演示这个概念:将未来传回给任务,让任务启动自己的计时器 - 计时器将在任务开始时启动。
以下代码添加了10个任务,每个任务需要2秒才能执行,但超时时间为1秒。
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class CancellableTaskDemo {
public static void main(final String[] args) {
new CancellableTaskDemo();
}
final ExecutorService ex = Executors.newFixedThreadPool(3);
public CancellableTaskDemo() {
for (int i = 0; i < 10; i++) {
final int c = i;
submitTask(new Callable<Object>() {
@Override
public Object call() throws Exception {
final long t = System.currentTimeMillis();
try {
Thread.sleep(2000);
System.out.println("Task " + c + " done in " + (System.currentTimeMillis() - t) + "ms");
} catch (final InterruptedException e) {
System.out.println("Task " + c + " aborted after " + (System.currentTimeMillis() - t) + "ms");
}
return null;
}
}, 1000);
}
ex.shutdown();
try {
ex.awaitTermination(100000, TimeUnit.MILLISECONDS);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
private void submitTask(final Callable<Object> c, final int timeout) {
final TimedFutureTask tft = new TimedFutureTask(c, timeout);
final Future<?> ft = ex.submit(tft.getCallable());
tft.setFuture(ft);
}
static class TimedFutureTask {
final static ScheduledExecutorService canceller = Executors.newSingleThreadScheduledExecutor();
private Timer cancelTimer;
private Callable<Object> timedCallable;
private Future<?> f;
private int timeoutMS;
public TimedFutureTask(final Callable<Object> callable, final int timeoutMS) {
this.timeoutMS = timeoutMS;
timedCallable = (new Callable<Object>() {
@Override
public Object call() throws Exception {
cancelTimer = new Timer();
cancelTimer.schedule(new TimerTask() {
@Override
public void run() {
f.cancel(true);
}
}, timeoutMS);
final Object res = callable.call();
cancelTimer.cancel();
return res;
}
});
}
public Callable<Object> getCallable() {
return timedCallable;
}
public void setFuture(final Future<?> future) {
f = future;
}
}
}
答案 1 :(得分:0)
我会使用ScheduleExecutorService。
final Future future = es.submit(myTask);
ses.schedule(new Runnable() {
public void run() {
future.cancel(true);
}
}, timeout, timeUnit);
答案 2 :(得分:0)
你可以手动完成,但是它的代码太多了,无法完成一项简单的任务:(
public void run() {
long start = System.nanoTime();
long timeout = 60 * 1000;
do {
// Do work here
} while (TimeUnit.MICROSECONDS.convert(System.nanoTime() - start,
TimeUnit.MICROSECONDS)
- start > timeout);
}
答案 3 :(得分:0)
您可以将计时器作为您提交的任务的一部分启动,因此它将在执行任务时启动。只是,在这种情况下,你不能使用future.cancel,但你可以打断线程。根据你提交的任务,优雅和及时终止可以很容易或不。