Java 优雅地实现队列长度指标到 ExecutorServices

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2265869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 05:26:44  来源:igfitidea点击:

Elegantly implementing queue length indicators to ExecutorServices

javaconcurrencyqueueexecutorserviceexecutor

提问by Joonas Pulakka

Why, oh why doesn't java.util.concurrentprovide a queue length indicators for its ExecutorServices? Recently I found myself doing something like this:

为什么,哦,为什么不java.util.concurrent为其ExecutorServices提供队列长度指示符?最近我发现自己在做这样的事情:

ExecutorService queue = Executors.newSingleThreadExecutor();
AtomicInteger queueLength = new AtomicInteger();
...

public void addTaskToQueue(Runnable runnable) {
    if (queueLength.get() < MAX_QUEUE_LENGTH) {
        queueLength.incrementAndGet(); // Increment queue when submitting task.
        queue.submit(new Runnable() {
            public void run() {
                runnable.run();
                queueLength.decrementAndGet(); // Decrement queue when task done.
            }
        });
    } else {
        // Trigger error: too long queue
    }
}

Which works ok, but... I think this really should be implemented as a part of the ExecutorService. It's dumb and error prone to carry around a counter separatedfrom the actual queue, whose length the counter is supposed to indicate (reminds me of C arrays). But, ExecutorServices are obtained via static factory methods, so there's no way to simply extend the otherwise excellent single thread executor and add a queue counter. So what should I do:

哪个工作正常,但是......我认为这真的应该作为ExecutorService. 携带一个与实际队列分开的计数器是愚蠢且容易出错的,计数器应该指示其长度(让我想起 C 数组)。但是,ExecutorServices 是通过静态工厂方法获得的,因此无法简单地扩展其他优秀的单线程执行器并添加队列计数器。所以我该怎么做:

  1. Reinvent stuff already implemented in JDK?
  2. Other clever solution?
  1. 重新发明已经在 J​​DK 中实现的东西?
  2. 其他聪明的解决方案?

采纳答案by x4u

There is a more direct way:

还有一个更直接的方法:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newSingleThreadExecutor();
// add jobs
// ...
int size = executor.getQueue().size();

Although you might consider not to use the convenience create methods of Executor, but rather create the executor directly to get rid of the cast and thus be sure that the executor will always actually be a ThreadPoolExecutor, even if the implementation of Executors.newSingleThreadExecutorwould change some day.

尽管您可能会考虑不使用 Executor 的便利 create 方法,而是直接创建 executor 以摆脱强制转换,从而确保 executor 始终实际上是 a ThreadPoolExecutor,即使Executors.newSingleThreadExecutor某天的实现会改变。

ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>() );

This is directly copied from Executors.newSingleThreadExecutorin JDK 1.6. The LinkedBlockingQueuethat is passed to the constructor is actually the very object that you will get back from getQueue.

这是从Executors.newSingleThreadExecutorJDK 1.6 中直接复制的。该LinkedBlockingQueue传递给构造实际上是非常的对象,你将回来getQueue

回答by Alex

While you can check the queue size directly. Another way of dealing with a queue that's getting too long is making the internal queue bounded.

虽然您可以直接检查队列大小。处理队列太长的另一种方法是使内部队列有界。

public static
ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) {
  return new ThreadPoolExecutor(nThreads, nThreads,
                              5000L, TimeUnit.MILLISECONDS,
                              new ArrayBlockingQueue<Runnable>(queueSize, true));
}

This will cause RejectedExecutionExceptions (see this) when you exceed the limit.

当您超过限制时,这将导致 RejectedExecutionExceptions(请参阅)。

If you want to avoid the exception the calling thread can be hiHymaned to execute the function. See this SO questionfor a solution.

如果你想避免异常,可以劫持调用线程来执行函数。请参阅此 SO 问题以获取解决方案。

References

参考