Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/utils/ExclusiveExec.java @ 775:eedad2ddad14
Removed race-condition while shapefile creation (issue164).
gnv-artifacts/trunk@841 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Ingo Weinzierl <ingo.weinzierl@intevation.de> |
---|---|
date | Fri, 26 Mar 2010 15:20:32 +0000 |
parents | |
children | 9a828e5a2390 |
comparison
equal
deleted
inserted
replaced
774:d0a39efbfd96 | 775:eedad2ddad14 |
---|---|
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(String)} to | |
8 * 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(String)}. 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 Sascha L. Teichmann (sascha.teichmann@intevation.de) | |
15 * @author Ingo Weinzierl (ingo.weinzierl@intevation.de) | |
16 */ | |
17 public final class ExclusiveExec | |
18 { | |
19 public static final ExclusiveExec INSTANCE = new ExclusiveExec(); | |
20 | |
21 private HashMap tokens; | |
22 | |
23 public static class UniqueKey { | |
24 Object key; | |
25 int [] refs; | |
26 public UniqueKey(Object key) { | |
27 this.key = key; | |
28 refs = new int[1]; | |
29 } | |
30 } | |
31 | |
32 /** | |
33 * Private constructor. Use {@link #INSTANCE} instead. | |
34 */ | |
35 private ExclusiveExec() { | |
36 tokens = new HashMap(); | |
37 } | |
38 | |
39 /** | |
40 * This method serves a {@link UniqueKey} and starts a synchronized code | |
41 * block. | |
42 * | |
43 * @param key The key used to identify same threads. | |
44 * | |
45 * @return UniqueKey. Use this object to call {@link #release(UniqueKey)} | |
46 * at the end of your code being synchronized. | |
47 */ | |
48 public UniqueKey acquire(Object key) { | |
49 | |
50 try { | |
51 UniqueKey internalKey = null; | |
52 synchronized (tokens) { | |
53 internalKey = (UniqueKey)tokens.get(key); | |
54 | |
55 if (internalKey == null) { | |
56 tokens.put(key, internalKey = new UniqueKey(key)); | |
57 } | |
58 } | |
59 | |
60 synchronized (internalKey) { | |
61 ++internalKey.refs[0]; | |
62 while (internalKey.refs[0] > 1) { | |
63 internalKey.wait(10000L); | |
64 } | |
65 } | |
66 | |
67 return internalKey; | |
68 } | |
69 catch (InterruptedException ie) { | |
70 return null; | |
71 } | |
72 } | |
73 | |
74 /** | |
75 * This method releases a lock. Call this method at the end of your code | |
76 * being synchronized. | |
77 * | |
78 * @param internalKey Token retrieved by {@link #acquire(Object)}. | |
79 */ | |
80 public void release(UniqueKey internalKey) { | |
81 if (internalKey != null) { | |
82 synchronized (internalKey) { | |
83 if (--internalKey.refs[0] < 1) { | |
84 synchronized (tokens) { | |
85 tokens.remove(internalKey.key); | |
86 } | |
87 } | |
88 internalKey.notifyAll(); | |
89 } | |
90 } | |
91 } | |
92 } | |
93 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |