ThreadPoolExecutor and finalization

Peter Levart peter.levart at
Thu Nov 2 09:26:58 UTC 2017

On 11/02/2017 03:34 AM, David Holmes wrote:
> On 2/11/2017 3:46 AM, Peter Levart wrote:
>> On 11/01/17 13:34, David Holmes wrote:
>>> On 1/11/2017 10:20 PM, Peter Levart wrote:
>>>> On 11/01/17 10:04, David Holmes wrote:
>>>>> On 1/11/2017 6:16 PM, Peter Levart wrote:
>>>>>> On 11/01/17 02:49, David Holmes wrote:
>>>>>>> Hi Roger,
>>>>>>> On 31/10/2017 11:58 PM, Roger Riggs wrote:
>>>>>>>> Hi Peter,
>>>>>>>> Only native resources that do not map to the heap allocation/gc 
>>>>>>>> cycle need any kind
>>>>>>>> of cleanup.  I would work toward a model that encapsulates the 
>>>>>>>> reference to a native resource
>>>>>>>> with a corresponding allocation/release mechanism as you've 
>>>>>>>> described here and in the
>>>>>>>> thread on zip.
>>>>>>>> For cleanup purposes, the independence of each resource may 
>>>>>>>> improve robustness
>>>>>>>> by avoiding dependencies and opportunities for entanglements 
>>>>>>>> and bugs due to exceptions
>>>>>>>> and other failures.
>>>>>>>> In the case of TPE, the native resources are Threads, which 
>>>>>>>> keep running even if they are
>>>>>>>> unreferenced and are kept referenced via ThreadGroups.
>>>>>>>> I don't know the Executor code well enough to do more than 
>>>>>>>> speculate, but would suggest
>>>>>>>> that a cleaner (or similar) should be registered for each thread .
>>>>>>> Threads are not native resources to be managed by Cleaners! A 
>>>>>>> live Thread can never be cleaned. A dead thread has nothing to 
>>>>>>> clean!
>>>>>> Right, but an idle thread, waiting for a task that will never 
>>>>>> come since the only entry point for submitting tasks is not 
>>>>>> reachable (the pool), may be cleaned...
>>>>> cleaned? It can be interrupted if you know about it and find 
>>>>> locate it. But it will not be eligible for cleaning ala Cleaner as 
>>>>> it will always be strongly reachable.
>>>> Ah I see what you meant before. Yes, tracking Thread object with a 
>>>> Cleaner does not have any sense. But tracking thread pool object 
>>>> with a Cleaner and cleaning (stopping) threads as a result makes 
>>>> sense...
>>> No, because live Threads will keep the thread pool strongly reachable.
>>> If you manage to structure things such that the Threads don't keep 
>>> the pool strongly reachable then you risk having the pool cleaned 
>>> while still actively in use.
>> Pool is actively in use when it is still reachable. Only in that case 
>> can new tasks be submitted. When it is not reachable any more, no new 
>> tasks can be submitted and it can be shutdown():
>>      /**
>>       * Initiates an orderly shutdown in which previously submitted
>>       * tasks are executed, but no new tasks will be accepted...
> Didn't we already determine that a Cleaner can't call shutdown() 
> because that requires a strong reference it doesn't have?

It can't call shutdown() on a tracked pool object, but it could do 
something that acted equivalently as shutdown().

> I think Doug already summed this up. The existing finalize() is 
> pointless because when it could be called there is nothing left to be 
> "cleaned up". There's no need for any use of Cleaner (even if it could 
> do anything useful).

There's no need for finalize() or Cleaner in existing TPE as is, I 
agree. But there could be a thread pool that would self-shutdown when it 
is of no use any more (either using finalize() or Cleaner). For example, 
here is such pool:

public class CleanableExecutorService implements ExecutorService {
     private final ThreadPoolExecutor tpe;

     public CleanableExecutorService(ThreadPoolExecutor tpe) {
         CleanerFactory.cleaner().register(this, tpe::shutdown);
         this.tpe = tpe;

     // implement and delegate all ExecutorService methods to tpe...

Regards, Peter

> David

More information about the core-libs-dev mailing list