Monitoring wrapped ThreadPoolExecutor returned from Executors

Tommy Ludwig tludwig at
Fri Jan 15 10:51:42 UTC 2021

Parsing the delegate toString would be a usable workaround for the time being for Micrometer, assuming the format is stable across JDK versions. It's better than no alternative, which is where I think we are currently at for the wrapped cases.

On 2021/01/09 1:24, "Doug Lea" <dl at> wrote:

    On 1/7/21 12:57 PM, Jason Mehrens wrote:
    > Hi Doug,
    > What are your thoughts on promoting monitoring methods from TPE and or FJP to AbstractExecutorService?  The default implementations could just return -1.  An example precedent is OperatingSystemMXBean::getSystemLoadAverage.  The Executors.DelegatedExecutorService could then be modified to extend AbstractExecutorService and forward the new methods and the existing AES::taskFor calls when the wrapped Executor is also an AbstractExecutorService.  The return types of the Executors.newXXX would remain the same.

    Maybe. But for now, here's a cheap trick that might be tolerable: Add to 

    public String toString() { return e.toString(); }

    The juc executors (ThreadPoolExecutor and ForkJoinPool that could be 
    wrapped here) both print pool size, active threads, queued tasks, and 
    completed tasks. It would require not-very-pleasant string parsing in 
    monitoring tools, but this might be good enough for Micrometer and others?

    > I suppose the tradeoff is that adding any new default method to ExecutorService and or new methods to AbstractExecutorService could break 3rd party code.
    > Jason
    > ________________________________________
    > From: core-libs-dev <core-libs-dev-retn at> on behalf of Doug Lea <dl at>
    > Sent: Thursday, January 7, 2021 7:09 AM
    > To: core-libs-dev at
    > Subject: Re: Monitoring wrapped ThreadPoolExecutor returned from Executors
    > On 1/5/21 10:11 PM, Tommy Ludwig wrote:
    >> In the Micrometer project, we provide metrics instrumentation of `ExectorService`s. For `ThreadPoolExecutor`s, we track the number of completed tasks, active tasks, thread pool sizes, task queue size and remaining capacity via methods from `ThreadPoolExecutor`. We are currently using a brittle reflection hack[1] to do this for the wrapped `ThreadPoolExecutor` returned from `Executors` methods `newSingleThreadExecutor` and `newSingleThreadScheduledExecutor`. With the introduction of JEP-396 in JDK 16, our reflection hack throws an InaccessibleObjectException by default.
    >> I am not seeing a proper way to get at the methods we use for the metrics (e.g. `ThreadPoolExecutor::getCompletedTaskCount`) in this case. Is there a way that I am missing?
    > There's no guarantee that newSingleThreadExecutor returns a restricted
    > view of a ThreadPoolExecutor, so there can't be a guaranteed way of
    > accessing it,
    > But I'm sympathetic to the idea that under the current implementation
    > (which is unlikely to change anytime soon), the stats are available, and
    > should be available to monitoring tools. But none of the ways to do this
    > are very attractive: Creating a MonitorableExecutorService interface and
    > returning that? Making the internal view class public with a protected
    > getExecutor method?

More information about the core-libs-dev mailing list