Created
February 22, 2020 20:04
-
-
Save volyx/6f231b00820bede9a73896ded69a3029 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.ScheduledThreadPoolExecutor; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.atomic.AtomicInteger; | |
public class Test { | |
private static final AtomicInteger poolNumber = new AtomicInteger(1); | |
private static final AtomicInteger threadNumber = new AtomicInteger(1); | |
private static final ScheduledThreadPoolExecutor executor = useDaemonThreadFactory(new ScheduledThreadPoolExecutor(1)); | |
public static void main(String[] args) throws InterruptedException, IOException { | |
executor.execute(() -> { | |
System.out.println("start " + ProcessHandle.current().pid()); | |
while (true); | |
}); | |
Runtime.getRuntime().addShutdownHook(new Thread(() -> { | |
System.out.println("start hook"); | |
shutdownAndAwaitTermination(executor, 30, TimeUnit.SECONDS); | |
System.out.println("end hook"); | |
})); | |
Thread.sleep(5000); | |
new ProcessBuilder("kill", "-15", Long.toString(ProcessHandle.current().pid())).start(); | |
} | |
public static ScheduledThreadPoolExecutor useDaemonThreadFactory(ScheduledThreadPoolExecutor executor) { | |
executor.setThreadFactory(r -> { | |
SecurityManager s = System.getSecurityManager(); | |
ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); | |
String namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; | |
Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0); | |
// t.setDaemon(Boolean.parseBoolean("daemon")); | |
if (t.getPriority() != Thread.NORM_PRIORITY) | |
t.setPriority(Thread.NORM_PRIORITY); | |
return t; | |
}); | |
return executor; | |
} | |
/** | |
* Shuts down the given executor service gradually, first disabling new submissions and later, if | |
* necessary, cancelling remaining tasks. | |
* | |
* <p>The method takes the following steps: | |
* <ol> | |
* <li>calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. | |
* <li>awaits executor service termination for half of the specified timeout. | |
* <li>if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling pending | |
* tasks and interrupting running tasks. | |
* <li>awaits executor service termination for the other half of the specified timeout. | |
* </ol> | |
* | |
* <p>If, at any step of the process, the calling thread is interrupted, the method calls | |
* {@link ExecutorService#shutdownNow()} and returns. | |
* | |
* @param service the {@code ExecutorService} to shut down | |
* @param timeout the maximum time to wait for the {@code ExecutorService} to terminate | |
* @param unit the time unit of the timeout argument | |
* @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} | |
* if the call timed out or was interrupted | |
* @since 17.0 | |
*/ | |
public static boolean shutdownAndAwaitTermination( | |
ExecutorService service, long timeout, TimeUnit unit) { | |
long halfTimeoutNanos = unit.toNanos(timeout) / 2; | |
// Disable new tasks from being submitted | |
System.out.println("start shutdown " + service.getClass()); | |
service.shutdown(); | |
try { | |
// Wait for half the duration of the timeout for existing tasks to terminate | |
if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) { | |
// Cancel currently executing tasks | |
System.out.println("start shutdownNow " + service.getClass()); | |
service.shutdownNow(); | |
// Wait the other half of the timeout for tasks to respond to being cancelled | |
service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS); | |
} | |
System.out.println("end shutdown " + service.getClass()); | |
} catch (InterruptedException ie) { | |
// Preserve interrupt status | |
// Thread.currentThread().interrupt(); | |
System.err.println(ie.getMessage()); | |
// (Re-)Cancel if current thread also interrupted | |
service.shutdownNow(); | |
} | |
return service.isTerminated(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment