使用 ExecutorService 执行限时任务

The*_*ode 1 java multithreading executorservice threadpoolexecutor

我有长时间运行的任务提交给ExecutorService. 该任务可能会运行相当长的时间。同时,新的任务被提交到内部阻塞队列。

提交的任务完成后,会发送回通知以从队列中释放任务以供执行。然而,有时,由于编程错误或网络问题,通知不会被触发。在这种情况下,我的任务队列可能会变得非常大,并且我可能会遇到任务可能永远留在队列中的情况。

为了克服这个问题,我正在考虑编写一个线程,该线程将定期检查任务在队列中空闲的时间。如果任务在队列中等待了 15 分钟,我会假设之前提交的任务遇到了错误,因此没有返回。然后我将从队列中逐出该任务并允许其执行。

是否有任何现有机制可以处理此问题,或者我必须编写此自定义逻辑?

注:
我不喜欢的原因ScheduledExecutor是因为并非所有任务都要定期执行。只有故障场景才应在一定延迟后执行。

编辑 架构的简要概述我正在设计的解决方案应该支持许多并发静态文件下载。通常可能有数千个下载请求。下载请求由基于 UI 的应用程序触发。这样我就知道何时会触发请求。利用这种方法,我打算限制下载请求。

当用户创建 300 个下载请求时会发生什么?

  1. 应用程序工作线程创建 300 个下载任务
  2. 提交了 100 个任务。我定义了最大 HTTP 线程池大小,例如 100。这意味着我可以支持最多 100 个同步并行下载 (servlet 2.5) 该任务反过来要求远程 HTTP 客户端执行 HTTP get。请注意,HTTP 线程尚未发挥作用
  3. 剩余 200 个请求正在排队。
  4. HTTP 客户端执行 HTTP Get。HTTP 线程现在以阻塞方式传输响应。
  5. 收到 200 OK 后,我会创建一条通知,通知其中一个客户端已完成下载。
  6. 现在,限制将释放/提交先前排队的 200 个请求中的任务之一。

在我能够接收响应(HTTP 200/HTTP 500 等)的情况下,限制机制就像一个魅力。但是,例如,servlet 本身抛出异常,我没有收到任何响应来表明 HTTP 工作线程是空闲的。因此,该任务有可能永远保留在队列中。为了克服这个问题,我正在考虑一种基于计时器的方法,如果 15 分钟内没有 HTTP 响应,则提交下一个队列任务来执行。一种避免重大内存泄漏的回退机制。

Boh*_*ian 5

通过超时调用来限制任务允许的最长时间get(),并在捕获时TimeoutException执行清理。

这是一个在等待时不会阻塞主线程的实现:

ExecutorService executor = Executors.newCachedThreadPool();
ExecutorService monitor = Executors.newFixedThreadPool(99);

public void submit(Runnable task) {
    Runnable monitorTask = new Runnable() {
        @Override
        public void run() {
            Future<?> future = executor.submit(task);
            try {
                future.get(15, TimeUnit.MINUTES);
            } catch (InterruptedException e) {
                // retry waiting. iterative approach not shown here
            } catch (ExecutionException e) {
                // your task exploded
            } catch (TimeoutException e) {
                // your task timed out - perform clean up, eg
                future.cancel(true);
            }               
        }
    };
    monitor.submit(monitorTask);
}
Run Code Online (Sandbox Code Playgroud)

使用单独的线程池来防止没有可监视的线程,但有可用于执行任务的线程导致不受监视的任务。