简体   繁体   English

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

[英]Can I run background tasks in a ThreadPool?

I have an ExecutorService to execute my tasks concurrently. 我有一个ExecutorService来同时执行我的任务。 Most of these tasks are simple actions that require ~300ms to complete each. 大多数这些任务都是简单的操作,每个任务需要大约300毫秒。 But a few of these tasks are background processing queues that take in new sub-tasks all the time and execute them in order. 但是其中一些任务是后台处理队列,它们始终接收新的子任务并按顺序执行它们。 These background tasks will remain active as long as there are normal tasks running. 只要正常任务正在运行,这些后台任务将保持活动状态。

The ThreadPool is generated through one of the Executors ' methods (don't know which yet) with a user-specified Thread count. ThreadPool是通过Executors的一个方法(不知道哪个)与用户指定的线程计数生成的。 My fear is that the following situation might happen: There are less threads than there are background queues. 我担心以下情况可能会发生:线程少于后台队列。 At a given moment, all background queues are working, blocking all the threads of the ExecutorService . 在给定时刻,所有后台队列都在工作,阻塞ExecutorService所有线程。 No normal tasks will thus be started and the program hang forever. 因此,不会启动正常任务,程序将永远挂起。

Is there a possibility this might happen and how can I avoid it? 是否有可能发生这种情况,我该如何避免呢? I'm thinking of a possibility to interrupt the background tasks to leave the place to the normal ones. 我正在考虑中断后台任务的可能性,让这个地方离开正常的地方。


The goal is to limit the number of threads in my application because Google said having a lot of threads is bad and having them idle for most of the time is bad too. 目标是限制我的应用程序中的线程数量,因为谷歌表示有很多线程是坏的,并且大部分时间让它们闲置也很糟糕。

There are ~10000 tasks that are going to be submitted in a very short amount of time at the begin of the program execution. 在程序执行开始时,将在很短的时间内提交约10000个任务。 About ~50 background task queues are needed and most of the time will be spent waiting for a background job to do. 大约需要大约50个后台任务队列,大部分时间都花在等待后台工作上。

Don't mix up long running tasks with short running tasks in same ExecutorService . 不要将长时间运行的任务与同一ExecutorService短期运行任务混淆。

Use two different ExecutorService instances with right pool size. 使用具有正确池大小的两个不同ExecutorService实例。 Even if you set the size as 50 for background threads with long running tasks, performance of the pool is not optimal since number of available cores (2 core, 4 core, 8 core etc.) is not in that number. 即使您将具有长时间运行任务的后台线程的大小设置为50,池的性能也不是最佳的,因为可用核心数(2核,4核,8核等)不在该数量中。

I would like to create two separate ExecutorService initialized with Runtime.getRuntime().availableProcessors()/2 ; 我想用Runtime.getRuntime().availableProcessors()/2初始化两个单独的ExecutorService Runtime.getRuntime().availableProcessors()/2 ;

Have a look at below posts for more details to effectively utilize available cores: 有关更多详细信息,请查看以下帖子以有效利用可用内核:

How to implement simple threading with a fixed number of worker threads 如何使用固定数量的工作线程实现简单线程

Dynamic Thread Pool 动态线程池

You can have an unlimited number of threads, check out cache thread pool 您可以拥有无​​限数量的线程,检查缓存线程池

Creates a thread pool that creates new threads as needed , but will reuse previously constructed threads when they are available. 创建一个根据需要创建新线程的线程池,但在它们可用时将重用以前构造的线程。 These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. 这些池通常会提高执行许多短期异步任务的程序的性能。 Calls to execute will reuse previously constructed threads if available. 如果可用,执行调用将重用先前构造的线程。 If no existing thread is available, a new thread will be created and added to the pool. 如果没有可用的现有线程,则将创建一个新线程并将其添加到池中。 Threads that have not been used for sixty seconds are terminated and removed from the cache. 未使用60秒的线程将终止并从缓存中删除。 Thus, a pool that remains idle for long enough will not consume any resources. 因此,长时间闲置的池不会消耗任何资源。 Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors. 请注意,可以使用ThreadPoolExecutor构造函数创建具有相似属性但不同详细信息的池(例如,超时参数)。

Another option is create two different pools and reserve one for priority tasks. 另一个选项是创建两个不同的池并为优先级任务保留一个池。

The solution is that the background tasks stop instead of being idle when there is no work and get restarted if there are enough tasks again. 解决方案是后台任务在没有工作时停止而不是空闲,如果有足够的任务就重新启动。

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();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM