我可以在ThreadPool中运行后台任务吗?

时间:2017-04-10 08:20:38

标签: java multithreading background-process executorservice

我有一个ExecutorService来同时执行我的任务。大多数这些任务都是简单的操作,每个任务需要大约300毫秒。但是其中一些任务是后台处理队列,它们始终接收新的子任务并按顺序执行它们。只要正常任务正在运行,这些后台任务就会保持活动状态。

ThreadPool是通过一个Executors'方法(不知道哪个)和用户指定的线程计数生成的。我担心以下情况可能会发生:线程少于后台队列。在给定时刻,所有后台队列都在工作,阻塞ExecutorService的所有线程。因此,不会启动任何正常任务,程序将永远挂起。

是否有可能发生这种情况,我该如何避免呢?我正在考虑中断后台任务的可能性,让这个地方离开正常的地方。

我的目标是限制我的应用程序中的线程数量,因为谷歌表示有很多线程是坏的,并且大部分时间让它们闲置也很糟糕。

在程序执行开始时,将在很短的时间内提交约10000个任务。大约需要约50个后台任务队列,大部分时间都花在等待后台工作上。

3 个答案:

答案 0 :(得分:2)

不要将长时间运行的任务与同一ExecutorService中的短期运行任务混淆。

使用具有正确池大小的两个不同ExecutorService个实例。即使您将具有长时间运行任务的后台线程的大小设置为50,池的性能也不是最佳的,因为可用核心数(2核,4核,8核等)不在该数量中。

我想创建两个单独的ExecutorService初始化Runtime.getRuntime().availableProcessors()/2;

请查看以下帖子,了解有效利用可用内核的更多详情:

How to implement simple threading with a fixed number of worker threads

Dynamic Thread Pool

答案 1 :(得分:1)

您可以拥有无​​限数量的主题,请查看cache thread pool

  

创建一个线程池,根据需要创建新线程,但是会   在先前构造的线程可用时重用它们。这些   池通常会提高执行程序的性能   许多短暂的异步任务。执行调用将重用   以前构造的线程(如果有)如果没有现有的线程   可用时,将创建一个新线程并将其添加到池中。主题   未使用60秒的任务将被终止并删除   从缓存。因此,一个长时间闲置的游泳池将会   不消耗任何资源。请注意具有相似属性的池   可以创建不同的细节(例如,超时参数)   使用ThreadPoolExecutor构造函数。

另一种选择是创建两个不同的池,并为优先级任务保留一个。

答案 2 :(得分:0)

解决方案是后台任务在没有工作时停止而不是空闲,如果有足够的任务就重新启动。

public class BackgroundQueue implements Runnable {

    private final ExecutorService service;
    private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
    private final AtomicBoolean running = new AtomicBoolean(false);
    private Future<?> future;

    public BackgroundQueue(ExecutorService service) {
        this.service = Objects.requireNonNull(service);
        // Create a Future that immediately returns null
        FutureTask f = new FutureTask<>(() -> null);
        f.run();
        future = f;
    }

    public void awaitQueueTermination() throws InterruptedException, ExecutionException {
        do {
            future.get();
        } while (!tasks.isEmpty() || running.get());
    }

    public synchronized void submit(Runnable task) {
        tasks.add(task);
        if (running.compareAndSet(false, true))
            future = service.submit(this);
    }

    @Override
    public void run() {
        while (!running.compareAndSet(tasks.isEmpty(), false)) {
            tasks.remove().run();
        }
    }
}