Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/utils/ExclusiveExec.java @ 1119:7c4f81f74c47
merged gnv-artifacts
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:00 +0200 |
parents | f953c9a559d8 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/utils/ExclusiveExec.java Fri Sep 28 12:14:00 2012 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ + +package de.intevation.gnv.utils; + +import java.util.HashMap; + +/** + * This class can be used to synchronize threads with a given key. To use this + * synchronization, you first need to do call {@link #acquire(java.lang.Object)} + * to retrieve a {@link UniqueKey}. After this, you can call the code being + * synchronized. After this execution, you need to call + * {@link #release(UniqueKey)} with your token you retrieved from {@link + * #acquire(java.lang.Object)}. A thread needs to wait for another thread if their keys + * are equal. Threads with different keys don't need to wait for each other. + * + * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public final class ExclusiveExec +{ + /** + * The only instance of this singleton. + */ + public static final ExclusiveExec INSTANCE = new ExclusiveExec(); + + private HashMap tokens; + + /** + * This class represents a unique key with a reference counter. + */ + public static class UniqueKey { + Object key; + int [] refs; + + /** + * Constructs a new UniqueKey. + * + * @param key The key of this unique key. + */ + public UniqueKey(Object key) { + this.key = key; + refs = new int[1]; + } + } + + /** + * Private constructor. Use {@link #INSTANCE} instead. + */ + private ExclusiveExec() { + tokens = new HashMap(); + } + + /** + * This method serves a {@link UniqueKey} and starts a synchronized code + * block. + * + * @param key The key used to identify same threads. + * @return UniqueKey. Use this object to call {@link #release(UniqueKey)} + * at the end of your code being synchronized. + */ + public UniqueKey acquire(Object key) { + + try { + UniqueKey internalKey = null; + synchronized (tokens) { + internalKey = (UniqueKey)tokens.get(key); + + if (internalKey == null) { + tokens.put(key, internalKey = new UniqueKey(key)); + } + } + + synchronized (internalKey) { + ++internalKey.refs[0]; + while (internalKey.refs[0] > 1) { + internalKey.wait(10000L); + } + } + + return internalKey; + } + catch (InterruptedException ie) { + return null; + } + } + + /** + * This method releases a lock. Call this method at the end of your code + * being synchronized. + * + * @param internalKey Token retrieved by {@link #acquire(Object)}. + */ + public void release(UniqueKey internalKey) { + if (internalKey != null) { + synchronized (internalKey) { + if (--internalKey.refs[0] < 1) { + synchronized (tokens) { + tokens.remove(internalKey.key); + } + } + internalKey.notifyAll(); + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :