2

Per the ThreadPoolExecutor doc (Java ThreadPoolExecutor), if I create an executor service like so:

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

and when #threads > corePoolSize, idle threads will be killed. I wanted to call some application specific cleanup code when the ThreadPoolExecutor kills any thread. I wasn't able to get a clear way to do so. Appreciate any help. Thanks in advance.

Vaibhav Gumashta
  • 894
  • 11
  • 21
  • 1
    Have you considered giving the Executor your own implementation of a ThreadFactory, which in turns creates your own "I was killed" -sensing implementation of a Thread? – Fildor Aug 03 '14 at 12:43
  • See also [WeakReference](http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/ref/WeakReference.html) – Fildor Aug 03 '14 at 12:49
  • @Fildor Yup, I supplied my own factory which would create a new thread (which extends Thread class) that overrides the interrupt method, calling the custom cleanup code and then calling the interrupt method of the superclass. But it seems, while killing the thread, ThreadPoolExecutor does not seem to call the interrupt method. – Vaibhav Gumashta Aug 03 '14 at 12:51
  • 1
    I just looked at the implementation and I think overriding ``interrupt`` for starting cleanup is not what you want. When the worker Thread is "killed", the ThreadPool will just abandon the reference but not neccessarily call interrupt. And vice versa: When interupt is called, it does not mean the Thread is being killed. – Fildor Aug 03 '14 at 15:21
  • 1
    I guess you should have your ThreadFactory keep WeakReferences to the Threads it creates and register them with a ReferenceQueue. There they are enqueued when they get weakly reachable (all strong references are abandoned). That's what I would try. Maybe someone has a better (simpler) idea? – Fildor Aug 03 '14 at 15:23
  • @Fildor That looks like a better idea. Let me try that and update the thread. Thanks! – Vaibhav Gumashta Aug 03 '14 at 16:06
  • 1
    I've never needed this, which makes me suspect you have a design problem. – djechlin Aug 03 '14 at 17:58

1 Answers1

6

the correct way to do this is by extending Thread and running your cleanup code after the run() method returns, like so:

    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
    ThreadFactory threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r) {
                @Override
                public void run() {
                    super.run();
                    //DO YOUR CLEANUP HERE
                }
            };
        }
    };
    new ThreadPoolExecutor(1, 10, 10, TimeUnit.SECONDS, workQueue, threadFactory);

interrupt will almost definitely not get called in your scenario, since it will only be called when shutting down an active executor (and even then, not always).

by calling cleanup directly after run your cleanup code gets called right before the thread dies (a thread dies after the runnable's run() method returns).

radai
  • 23,949
  • 10
  • 71
  • 115
  • Great answer only has 1 defect: if you actually take the code and run it, you will end up with only 1 thread in the pool. This is due to the ArrayBlockingQueue work queue that you've supplied. If you change it work with SynchronousQueue the answer will be perfect! Now, why is that happening? This should be another "stackoverflow" question (if it is not already...) – shlomi33 Aug 03 '14 at 19:59
  • @shlomi33 - http://stackoverflow.com/questions/19528304/how-to-get-the-threadpoolexecutor-to-increase-threads-to-max-before-queueing – radai Aug 03 '14 at 20:22