为了账号安全,请及时绑定邮箱和手机立即绑定

请问在超时后中断任务的ExecutorService

/ 猿问

请问在超时后中断任务的ExecutorService

波斯汪 2019-10-21 16:12:31

在超时后中断任务的ExecutorService

我在找一个行政服务可以提供超时的实现。提交给ExecutorService的任务如果花费的时间超过运行超时时间,就会中断。实现这样一个猛兽并不是那么困难的任务,但我想知道是否有人知道一个现有的实现。

以下是我根据下面的一些讨论得出的结论。有什么评论吗?

import java.util.List;import java.util.concurrent.*;public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor {
    private final long timeout;
    private final TimeUnit timeoutUnit;

    private final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    private final ConcurrentMap<Runnable, ScheduledFuture> runningTasks = new ConcurrentHashMap<Runnable, ScheduledFuture>();

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable>
     workQueue, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> 
    workQueue, ThreadFactory threadFactory, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable>
     workQueue, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }


查看完整描述

3 回答

?
吃鸡游戏

您可以使用ScheduledExecutorService为了这个。首先,你只会提交一次,立即开始并保留所创造的未来。在此之后,您可以提交一个新任务,该任务将在一段时间后取消保留的未来。

 ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); 
 final Future handler = executor.submit(new Callable(){ ... });
 executor.schedule(new Runnable(){
     public void run(){
         handler.cancel();
     }      
 }, 10000, TimeUnit.MILLISECONDS);

这将执行处理程序(主要功能被中断)10秒,然后取消(即中断)特定的任务。



查看完整回答
反对 回复 2019-10-22
?
莫回无

不幸的是,解决办法是有缺陷的。有一种错误ScheduledThreadPoolExecutor,也在这个问题取消提交的任务并不能完全释放与任务相关的内存资源;只有在任务到期时才释放资源。

因此,如果创建一个TimeoutThreadPoolExecutor使用相当长的过期时间(一种典型的用法),并且提交任务足够快,您最终会填充内存-尽管这些任务实际上已经成功地完成了。

您可以看到以下(非常粗糙的)测试程序的问题:

public static void main(String[] args) throws InterruptedException {
    ExecutorService service = new TimeoutThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, 
            new LinkedBlockingQueue<Runnable>(), 10, TimeUnit.MINUTES);
    //ExecutorService service = Executors.newFixedThreadPool(1);
    try {
        final AtomicInteger counter = new AtomicInteger();
        for (long i = 0; i < 10000000; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    counter.incrementAndGet();
                }
            });
            if (i % 10000 == 0) {
                System.out.println(i + "/" + counter.get());
                while (i > counter.get()) {
                    Thread.sleep(10);
                }
            }
        }
    } finally {
        service.shutdown();
    }}

程序耗尽可用内存,尽管它等待生成的内存。Runnable我们要完成。

我想了一段时间,但不幸的是,我无法找到一个好的解决方案。

编辑:我发现这个问题被报道为JDK bug 6602600似乎是最近才修好的。



查看完整回答
反对 回复 2019-10-22
?
慕森王

将任务包装在FutureTask中,您可以为FutureTask指定超时。看看我回答这个问题的例子,

Java本机进程超时


查看完整回答
反对 回复 2019-10-22

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信