/******************************************************************************* * Copyright (c) 2013 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.utilbox.concurrency; import java.util.concurrent.CountDownLatch; import melnorme.utilbox.ownership.IDisposable; /** * A {@link LatchRunnable2} provides a two way (entry and exit) concurrency barrier. * It is useful mostly for tests related to concurrent code. * (Improved version over {@link LatchRunnable}) */ public class LatchRunnable2 implements Runnable { public final CountDownLatch entryLatch; public final CountDownLatch exitLatch; public LatchRunnable2() { this.entryLatch = new CountDownLatch(1); this.exitLatch = new CountDownLatch(1); } @Override public void run() { entryLatch.countDown(); try { doRun(); } finally { exitLatch.countDown(); } } protected void doRun() { } public void awaitEntry() { awaitLatch(entryLatch); } public void awaitExit() { awaitLatch(exitLatch); } public static void awaitLatch(CountDownLatch latch) { while(true) { try { latch.await(); return; } catch(InterruptedException e) { continue; } } } public void releaseAll() { entryLatch.countDown(); exitLatch.countDown(); } protected final IDisposable asDisposable = new IDisposable() { @Override public void dispose() { releaseAll(); // Ensure whatever was holding on the latch is released, even for error cleanup } }; public IDisposable asDisposable() { return asDisposable; } }