Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/utils/ExclusiveExec.java @ 875:5e9efdda6894
merged gnv-artifacts/1.0
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:56 +0200 |
parents | 22c18083225e |
children | f953c9a559d8 |
comparison
equal
deleted
inserted
replaced
722:bb3ffe7d719e | 875:5e9efdda6894 |
---|---|
1 package de.intevation.gnv.utils; | |
2 | |
3 import java.util.HashMap; | |
4 | |
5 /** | |
6 * This class can be used to synchronize threads with a given key. To use this | |
7 * synchronization, you first need to do call {@link #acquire(java.lang.Object)} | |
8 * to retrieve a {@link UniqueKey}. After this, you can call the code being | |
9 * synchronized. After this execution, you need to call | |
10 * {@link #release(UniqueKey)} with your token you retrieved from {@link | |
11 * #acquire(java.lang.Object)}. A thread needs to wait for another thread if their keys | |
12 * are equal. Threads with different keys don't need to wait for each other. | |
13 * | |
14 * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> | |
15 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
16 */ | |
17 public final class ExclusiveExec | |
18 { | |
19 /** | |
20 * The only instance of this singleton. | |
21 */ | |
22 public static final ExclusiveExec INSTANCE = new ExclusiveExec(); | |
23 | |
24 private HashMap tokens; | |
25 | |
26 /** | |
27 * This class represents a unique key with a reference counter. | |
28 */ | |
29 public static class UniqueKey { | |
30 Object key; | |
31 int [] refs; | |
32 | |
33 /** | |
34 * Constructs a new UniqueKey. | |
35 * | |
36 * @param key The key of this unique key. | |
37 */ | |
38 public UniqueKey(Object key) { | |
39 this.key = key; | |
40 refs = new int[1]; | |
41 } | |
42 } | |
43 | |
44 /** | |
45 * Private constructor. Use {@link #INSTANCE} instead. | |
46 */ | |
47 private ExclusiveExec() { | |
48 tokens = new HashMap(); | |
49 } | |
50 | |
51 /** | |
52 * This method serves a {@link UniqueKey} and starts a synchronized code | |
53 * block. | |
54 * | |
55 * @param key The key used to identify same threads. | |
56 * @return UniqueKey. Use this object to call {@link #release(UniqueKey)} | |
57 * at the end of your code being synchronized. | |
58 */ | |
59 public UniqueKey acquire(Object key) { | |
60 | |
61 try { | |
62 UniqueKey internalKey = null; | |
63 synchronized (tokens) { | |
64 internalKey = (UniqueKey)tokens.get(key); | |
65 | |
66 if (internalKey == null) { | |
67 tokens.put(key, internalKey = new UniqueKey(key)); | |
68 } | |
69 } | |
70 | |
71 synchronized (internalKey) { | |
72 ++internalKey.refs[0]; | |
73 while (internalKey.refs[0] > 1) { | |
74 internalKey.wait(10000L); | |
75 } | |
76 } | |
77 | |
78 return internalKey; | |
79 } | |
80 catch (InterruptedException ie) { | |
81 return null; | |
82 } | |
83 } | |
84 | |
85 /** | |
86 * This method releases a lock. Call this method at the end of your code | |
87 * being synchronized. | |
88 * | |
89 * @param internalKey Token retrieved by {@link #acquire(Object)}. | |
90 */ | |
91 public void release(UniqueKey internalKey) { | |
92 if (internalKey != null) { | |
93 synchronized (internalKey) { | |
94 if (--internalKey.refs[0] < 1) { | |
95 synchronized (tokens) { | |
96 tokens.remove(internalKey.key); | |
97 } | |
98 } | |
99 internalKey.notifyAll(); | |
100 } | |
101 } | |
102 } | |
103 } | |
104 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |