13

Lets assume I'm planning to use one executorservice in my entire application, to which I'm sending new runnable's or callable's to execute/submit, and I ommit to shutdown right after I do that. I just want to throw my "tasks" to the executorservice and let him handle them and execute them giving it's resources (how many threads he has available, and how many he can create if needed and then queue those tasks accordingly).

From your experience of using ExecutorService in Android application, and taking into account the application state changes, if I don't want to constantly shutdown and re-create the executorservice by doing this:

    executor = Executors.newCachedThreadPool();
    executor.submit(some Runnable);
    executor.shutdown();

, what time and where would you reccomend to shutdown service, and then reinstate it so that I can prevent some leaks or some unforseen consequences?

I'm mostly reffering to:

1) Closing app by back button on the last activity in the backstack (Application uses many activities) 2) Application going in the background (on any of those activities) 3) Application going back into foreground (on any of those activities)

Lucas
  • 3,521
  • 3
  • 27
  • 39
  • 2
    Anybody with some good tips on when shutting down a single (or closed set) ExecutorService that was started at the start of an application? If the ExecutorService is not shutdown, it will not be garbage collected, and in effect the application will not be garbage collected (if the tasks given to executor service hold some references to say Activity, or some other key object) even if it's closed. Is there any grace way to do it? So far, I called shutdown everytime I submited something, and in effect I recreated ExecutorService over and over again. Not good solution in my eyes... – Lucas Dec 01 '13 at 10:43

3 Answers3

16

You can do one work around. Create the executor as daemon. Then it will automatically end when your application exits. You don't have to explicitly call the shutdown.

 ExecutorService es = Executors.newSingleThreadExecutor( new ThreadFactory() {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
});
Manu Viswam
  • 1,606
  • 2
  • 18
  • 33
  • I actually forgot about it, but found this suggestion somewhere in relation to something else, and already implemented it sometime ago. However, since you responded, checkmark is yours. – Lucas Mar 05 '14 at 13:52
7

I have a singleton instance of an ExecutorService which is scoped to the Android application instance via Dagger's object graph. So the instance lives as long as the Application object itself. Since Android's Application class offers no onDestroy() callback, it is never known when shutdown() should be called on the ExecutorService.

As I was afraid of memory leaks, I was also looking into ThreadPoolExecutor and playing with it to find out. This is what I found: Executors.newCachedThreadPool() creates a ThreadPoolExecutor with the following parameters:

ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

That is a corePoolSize of 0, which means that a minimum number of 0 worker threads is kept alive, so none. When the TPE (a.k.a ExecutorService) executes a task, it creates a worker thread and adds it to the pool. Now when no new task comes in during the timeout of 60 secs, the (still kept alive) worker thread is terminated and removed from the pool (cache).

For me that means that there won't be a memory leak, even when shutdown() is never called on the ExecutorService, as all worker threads that ever exist, time out and will be removed from the pool when no new task come in during the timeout period. I guess that that way, there wont be any references to worker threads left in the pool and so the GC can clean up the TPE instance.

Feel free to correct me if I'm wrong.

Sebastian Engel
  • 3,500
  • 32
  • 30
  • 2
    Awsome find. Thanks Sebastian. I did a small test just now and indeed it does behave exactly as you pointed out, and as written in the documentation of ThreadPoolExecutor. This seems to be the second solution, and more preferred if one doesn't want to make the Threads as Deamons. You can also change the KeepAlive setting if you cast the ExecutorService to ThreadPoolExecutor. So to finish, I don't see anything wrong with the case you presented and I will deffinetly try to use it in next project of mine. – Lucas Nov 21 '14 at 08:14
0

Although it's been years this question was posted, recently Android API 30 has deprecated AsyncTask and someone might get stuck here. To answer the question, there is no need to shutdown a singleton ExecutorService unless it has any idle thread. According to Oracle docs:

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...

The Executors.newCachedThreadPool() is a good factory method for this case. When your application process dies, it will automatically shutdown.

MyApplication.java:

public class MyApplication extends Application {
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    ...
    public static Executor getExecutor() {
        return executorService;
    }
}

Simply use MyApplication.getExecutor() anywhere in your code.

Ananta Raha
  • 1,011
  • 5
  • 14