优雅地为 ExecutorServices 实现队列长度指示器

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

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

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
    }
}

哪个工作正常,但是...我认为这确实应该作为 ExecutorService 的一部分来实现.从实际队列中携带一个 分离 的计数器是愚蠢且容易出错的,计数器应该指示其长度(让我想起了 C 数组).但是,ExecutorService 是通过静态工厂方法获得的,所以没有办法简单地扩展其他优秀的单线程执行器并添加队列计数器.那我该怎么办:

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 separated from 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:

  1. 重新发明已经在 J​​DK 中实现的东西?
  2. 其他巧妙的解决方案?

推荐答案

还有更直接的方法:

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

虽然您可能会考虑不使用 Executor 的便捷创建方法,而是直接创建 executor 以摆脱强制转换,从而确保 executor 实际上始终是 ThreadPoolExecutor,即使 Executors.newSingleThreadExecutor 的实现有一天会改变.

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.newSingleThreadExecutor would change some day.

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

这是直接从 JDK 1.6 中的 Executors.newSingleThreadExecutor 复制而来的.传递给构造函数的 LinkedBlockingQueue 实际上就是您将从 getQueue 得到的对象.

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

相关文章