ThreadPoolExecutor and finalization

David Holmes david.holmes at oracle.com
Thu Nov 2 12:47:25 UTC 2017


On 2/11/2017 7:26 PM, Peter Levart wrote:
> 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...
> }

Ah I see - the old "extra level of indirection" solution. :) The Cleaner 
keeps the tpe strongly reachable, but as soon as the holder class 
becomes "unreachable" the Cleaner will shutdown the tpe.

Though if you plan on abandoning a TPE such that you can't shutdown 
directly, then you may as well just configure it so all the threads 
terminate and it will "self-clean".

Cheers,
David

> Regards, Peter
> 
>>
>> David
> 


More information about the core-libs-dev mailing list