package freenet.node; import static java.util.concurrent.TimeUnit.SECONDS; import java.util.ArrayList; public class SemiOrderedShutdownHook extends Thread { private static final long TIMEOUT = SECONDS.toMillis(100); private final ArrayList<Thread> earlyJobs; private final ArrayList<Thread> lateJobs; public static final SemiOrderedShutdownHook singleton = new SemiOrderedShutdownHook(); static { Runtime.getRuntime().addShutdownHook(singleton); } public static SemiOrderedShutdownHook get() { return singleton; } private SemiOrderedShutdownHook() { earlyJobs = new ArrayList<Thread>(); lateJobs = new ArrayList<Thread>(); } public synchronized void addEarlyJob(Thread r) { earlyJobs.add(r); } public synchronized void addLateJob(Thread r) { lateJobs.add(r); } @Override public void run() { System.err.println("Shutting down..."); // First run early jobs, all at once, and wait for them to all complete. Thread[] early = getEarlyJobs(); for(Thread r : early) { r.start(); } for(Thread r : early) { try { r.join(TIMEOUT); } catch (InterruptedException e) { // :( // May as well move on } } Thread[] late = getLateJobs(); // Then run late jobs, all at once, and wait for them to all complete (JVM will exit when we return). for(Thread r : late) { r.start(); } for(Thread r : late) { try { r.join(TIMEOUT); } catch (InterruptedException e) { // :( // May as well move on } } } private synchronized Thread[] getEarlyJobs() { return earlyJobs.toArray(new Thread[earlyJobs.size()]); } private synchronized Thread[] getLateJobs() { return lateJobs.toArray(new Thread[lateJobs.size()]); } }