ExecutorService,用于扩展线程,然后对任务进行排队

时间:2015-04-29 12:11:41

标签: java multithreading executorservice

是否有ExecutorService实现,其行为类似于具有以下特征的线程池?

  1. 总是至少有X个活动线程。
  2. 如果提交任务且所有活动线程都忙,则启动新线程,最多为Y个线程。
  3. 如果提交任务且所有Y个线程都忙,则任务排队。
  4. 如果未提交任何新任务,则池会缩减为X活动线程。
  5. 非常标准的线程池行为。您认为ThreadPoolExecutor会处理此问题,但

    executorService = new ThreadPoolExecutor(
        2, 10, // min/max threads
        60, TimeUnit.SECONDS, // time of inactivity before scaling back
        new SynchronousQueue<Runnable>()); // task queue
    
    如果提交的任务超过10个,

    将抛出异常。切换到LinkedBlockingQueue将永远不会扩展到两个最小线程之外,除非您将大小限制为new LinkedBlockingQueue<Runnable>(20),在这种情况下,将有两个线程处理1-20个任务,2-10个线程处理21 -30个任务,超过30个任务的例外。不漂亮。同时,固定的线程池永远不会缩小非活动线程。

    所以,为了得到我所追求的东西,我可以使用不同类型的BlockingQueue或摆弄一些我错过的其他设置吗?是否有另一个ExceutorService实现更适合(哪个?),或者我最好通过覆盖execute()的{​​{1}}方法自行滚动?

2 个答案:

答案 0 :(得分:6)

不幸的是,答案是否定的。关于jre中最好的事情就是有效地没有螺纹地板,只有天花板。这可以通过allowing core threads to timeout完成。

ThreadPoolExecutor tpe = new ThreadPoolExecutor(10, 10, 60, TimeUnit.Seconds, new LinkedBlockingQueue<Runnable>());
tpe.allowCoreThreadTimeOut(true);

由于核心大小为10,因此在提交任务直到10个线程处于活动状态时将启动新线程。之后,任务将在LinkedBlockingQueue中排队。如果一个线程已经处于非活动状态60秒,它将终止。

通过编写实现BlockingQueue和RejectedExecutionHandler的类,可以实现所需的行为,该类检查ThreadPoolExecutors当前状态,然后确定是否应将任务添加到队列中或拒绝该任务。

答案 1 :(得分:0)

这应该可以解决问题:

    ThreadPoolExecutor tpe = new ThreadPoolExecutor(1, maxPoolSize, 60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());
    tpe.setRejectedExecutionHandler((
            Runnable r,
            ThreadPoolExecutor executor) -> {
        // this will block if the queue is full but not until the sun will rise in the west!
            try {
                if(!executor.getQueue().offer(r, 15, TimeUnit.MINUTES)){
                    throw new RejectedExecutionException("Will not wait infinitely for offer runnable to ThreadPoolExecutor");
                }
            } catch (InterruptedException e) {
                throw new RejectedExecutionException("Unable to put runnable to queue", e);
            }
        });