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