Reputation: 11387
There is an utility class called "ConcurrencyUtils" that uses ExecutorService internally
private static final ExecutorService executor = Executors.newCachedThreadPool(new CommonPoolThreadFactory());
as you can see it uses a thread pool that will add threads on demand. The problem is that if there is at least one thread in that pool (if util is used at least once) then when main method execution finishes application however didnt shut down, as the threads are still alive and are not garbage collected...
initially i've tried to use
public static void close(){
executor.shutdown();
}
and call it when the programm naturally should stop its execution. But there is no guarantee that main method is the last one to be finished and there can be other tasks that should finish before application will be terminated thus I dont know where do i call "close()" to clear up threads in util...
I wonder if community can hint me a smarter/cleaner way to implement this?
ConcurrencyUtil is intended to be available for use from everywhere and I cannot create an instance of it I need it to provide its interface through static not instance methods.
Let me explain this case in detail, ConcurrencyUtil has its own implementation of pool, and it provides usefull methods to chain several runnables and execute them in paralell or make some of them wait for otherso to finish and then execute... doesent matter it should be an utility class so that whenever you want you use async() or chain() and dont wory how it works.
Now the sample code :
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("hoooooooooooook");
}
});
ConcurrencyUtil.chain()
.add(()->System.out.println("task 1"))
.add(()->System.out.println("task 2"))
.execute()
.join();
System.out.println("main finish");
}
When this executes i'll have this :
created new thread with name [common-pool : thread-1]
created new thread with name [common-pool : thread-2]
task 1
task 2
main finish
As you can see thread pool creates two threads and executes concurrent tasks but those worker threads are still alive (in sleep) waiting for new task, thats why after main execution is finished application is still running... And shutdown hook is not working too as (i suppose) application is considered as alive...
Now given that I have no guarantee that main method is my exit point (it might be a runnable that finishes execution for example if i remove .join() ) thats why i cant put finally block and shut down ConcurrencyUtil...
Any ideas how can this be done properly?
Upvotes: 1
Views: 747
Reputation: 200236
The proper approach to application design is to introduce an explicit shutdown procedure, which is called from wherever appropriate. This procedure can then call shutdown()
on your executor service, followed by awaitTermination()
. Look into the Javadoc of ExecutorService
for a full code example.
In addition to the regular shutdown protocol you can provide a JVM shutdown hook, which will again initiate the same shutdown procedure. You should never rely on that mechanism, but it is a good thing to have in case of unpredictable failures.
Upvotes: 1