开发者

Why doesn't this thread pool get garbage collected?

开发者 https://www.devze.com 2023-04-12 19:13 出处:网络
In this code example, the ExecutorService is used one and allowed to go out of scope. public static void main(String[] args)

In this code example, the ExecutorService is used one and allowed to go out of scope.

public static void main(String[] args)
{
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    executorService.submit(new Runnable()
    {
        public void run()
        {
            System.out.println("hello");
        }
    });
}

Once executorService is out of scope, it should get collected and finalized. The finalize() method in ThreadPoolExecutor calls shutdown().

/**
 * Invokes {@code shutdown} when this executor is no longer
 * referenced and it has no threads.
 */
protec开发者_如何学JAVAted void finalize() {
    shutdown();
}

Once shutdown() is called, the pool threads should terminate and the JVM should be allowed to exit. However the executorSerivce is never getting collected and thus the JVM stays alive. Even calls to System.gc() don't seem to work. Why isn't executorService getting collected even after main() terminates?

Note: I know I should call shutdown() myself and I always do outside of testing. I'm curious why finalization isn't working as a back-up here.


This doesn't really have anything to do with GC being non-deterministic, although it doesn't help! (That is one cause in your example, but even if we 'fixed' it to eat up memory and force a collection, it still wouldn't finalize)

The Worker threads that the executor creates are inner classes that have a reference back to the executor itself. (They need it to be able to see the queue, runstate, etc!) Running threads are not garbage collected, so with each Thread in the pool having that reference, they will keep the executor alive until all threads are dead. If you don't manually do something to stop the threads, they will keep running forever and your JVM will never shut down.


Affe is correct; the thread pool's threads will keep it from being garbage collected. When you call Executors.newFixedThreadPool(3) you get a ThreadPoolExecutor constructed like so:

ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

And if you read the JavaDoc for ThreadPoolExecutor it says:

A pool that is no longer referenced in a program AND has no remaining threads will be shutdown automatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to call shutdown(), then you must arrange that unused threads eventually die, by setting appropriate keep-alive times, using a lower bound of zero core threads and/or setting allowCoreThreadTimeOut(boolean).

If you want your thread pool to finalize like you're expecting, you should do one of those things.


If you want the threads to be finalized when the Executor service is out of scope you should avoid, as mjt suggested, the use of

    ExecutorService executorService = Executors.newFixedThreadPool(3);`

and use for example:

ExecutorService executorService = new ThreadPoolExecutor(0, 3, 10, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());


Because garbage collection is “non deterministic” ie you cannot predict when it will happen, you thus cannot predict exactly when the finalize method will run. You can only make Objects eligible for GC and suggest gc with System.gc() without any guarantee.

Even worse threads are OS specific handled by the JVM and are hardly predictable...


Finalizers are too unpredictable. Depending on them is usually bad practice. You can read more about it in "Effective java" by Joshua Bloch (item 1.7)


Once executorService is out of scope, it should get collected and finalized.

Not really - once it is out of scope, it could get collected and finalized. There are no guarantees made in the VM spec about when objects are finalized, or even if they are finalized:

The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

0

精彩评论

暂无评论...
验证码 换一张
取 消