package games.strategy.util; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; /** * A handler for CountDownLatch's with methods to release latches being waited on from outside of their threads. * Is Thread Safe. */ public class CountDownLatchHandler { private final List<CountDownLatch> m_latchesToCloseOnShutdown = new ArrayList<>(); private volatile boolean m_isShutDown = false; private final boolean m_releaseLatchOnInterrupt; public CountDownLatchHandler(final boolean releaseLatchOnInterrupt) { super(); m_releaseLatchOnInterrupt = releaseLatchOnInterrupt; } /** * If "releaseLatchOnInterrupt" was set to true (defaults to false) on construction of this handler, then interruptAll * will release and * remove all current latches. * Otherwise does nothing. */ public void interruptAll() { if (m_releaseLatchOnInterrupt) { for (final CountDownLatch latch : m_latchesToCloseOnShutdown) { removeShutdownLatch(latch); } } } /** * If "releaseLatchOnInterrupt" was set to true (defaults to false) on construction of this handler, then * interruptLatch will release and * remove the latch. * Otherwise does nothing. */ public void interruptLatch(final CountDownLatch latch) { if (m_releaseLatchOnInterrupt) { removeShutdownLatch(latch); } } public boolean isShutDown() { return m_isShutDown; } /** * Shuts down this handler by releasing all latches and clearing the list of latches being handled. */ public void shutDown() { synchronized (this) { if (m_isShutDown) { return; } m_isShutDown = true; } for (final CountDownLatch latch : m_latchesToCloseOnShutdown) { releaseLatch(latch); } m_latchesToCloseOnShutdown.clear(); } /** * Utility method to fully release any CountDownLatch. */ private static void releaseLatch(final CountDownLatch latch) { if (latch == null) { return; } while (latch.getCount() > 0) { latch.countDown(); } } /** * Add a latch that will be released when this handler shuts down. * If this handler is already shutdown, then we will release the latch immediately. */ public void addShutdownLatch(final CountDownLatch latch) { synchronized (this) { if (m_isShutDown) { releaseLatch(latch); return; } m_latchesToCloseOnShutdown.add(latch); } } /** * Releases the latch and removes it from the latches being handled by this handler. */ public void removeShutdownLatch(final CountDownLatch latch) { removeShutdownLatch(latch, false); } /** * Removes the latch from the latches being handled by this handler, and will not release it if doNotRelease is true. */ public void removeShutdownLatch(final CountDownLatch latch, final boolean doNotRelease) { synchronized (this) { if (!doNotRelease) { releaseLatch(latch); } m_latchesToCloseOnShutdown.remove(latch); } } }