使用ExectutorService

时间:2015-07-20 11:07:04

标签: java multithreading executorservice threadpoolexecutor

我将长期运行的任务提交给ExecutorService。这项任务可能会持续一段时间。同时,新任务将提交到内部阻塞队列。

完成提交的任务后,将发回通知以从队列中释放任务以供执行。但是,有时,由于编程错误或网络问题,通知不会被触发。在这种情况下,我的任务队列可能会变得很大,我可能会遇到一个任务可能永远存在于队列中的情况。

为了解决这个问题,我正在考虑编写一个线程,该线程将定期检查任务在队列中处于空闲状态的时间。如果任务在队列中说15分钟,我将假设先前提交的任务遇到错误,因此没有返回。然后我将从队列中逐出任务并允许它被执行。

是否有任何现有的机制来处理这个问题,或者我必须编写这个自定义逻辑?

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

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

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

  1. 应用程序工作线程创建300个下载任务
  2. 提交了100个任务。我有一个定义的MAX HTTP线程池大小为100。这意味着我可以支持最多100个同步并行下载(servlet 2.5)该任务反过来要求远程HTTP客户端执行HTTP get 。请注意,HTTP线程尚未播放
  3. 剩余的200个请求排队。
  4. HTTP客户端执行HTTP Get。 HTTP线程现在以BLOCKING方式流式传输响应。
  5. 收到200 OK后,我会创建一个通知,告知其中一位客户已完成下载。
  6. 现在,油门将从先前排队的200个请求中释放/提交任务之一。
  7. 在我能够接收响应(HTTP 200 / HTTP 500等)的情况下,限制机制就像魅力一样。但是,例如,如果说servlet本身引发了异常,我就没有得到任何响应来指示HTTP工作线程是空闲的。因此,任务有可能永远保留在队列中。为了克服这个问题,我考虑了一种基于计时器的方法,如果15分钟内没有HTTP响应,则提交下一个队列任务以供执行。一种回退机制,以避免重大内存泄漏。

1 个答案:

答案 0 :(得分:4)

通过超时调用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);
}

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