KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > nightlabs > util > RWLockMan


1 /* ************************************************************************** *
2  * Copyright (C) 2004 NightLabs GmbH, Marco Schulze *
3  * All rights reserved. *
4  * http://www.NightLabs.de *
5  * *
6  * This program and the accompanying materials are free software; you can re- *
7  * distribute it and/or modify it under the terms of the GNU General Public *
8  * License as published by the Free Software Foundation; either ver 2 of the *
9  * License, or any later version. *
10  * *
11  * This module is distributed in the hope that it will be useful, but WITHOUT *
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FIT- *
13  * NESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more *
14  * details. *
15  * *
16  * You should have received a copy of the GNU General Public License along *
17  * with this module; if not, write to the Free Software Foundation, Inc.: *
18  * 59 Temple Place, Suite 330 *
19  * Boston MA 02111-1307 *
20  * USA *
21  * *
22  * Or get it online: *
23  * http://www.opensource.org/licenses/gpl-license.php *
24  * *
25  * In case, you want to use this module or parts of it in a proprietary pro- *
26  * ject, you can purchase it under the NightLabs Commercial License. Please *
27  * contact NightLabs GmbH under info AT nightlabs DOT com for more infos or *
28  * visit http://www.NightLabs.com *
29  * ************************************************************************** */

30
31 package com.nightlabs.util;
32
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35
36 import org.apache.log4j.Level;
37 import org.apache.log4j.Logger;
38
39 /**
40  * This class is used by the RWLocks. There exists exactly one instance
41  * of RWLockMan which keeps track of which thread holds which locks and which
42  * thread waits for wich locks. It allows to detect dead locks. Never use this
43  * object directly! Use RWLock.
44  *
45  * @see RWLock
46  *
47  * @author Marco Schulze
48  * @version 1.0
49  */

50
51 public class RWLockMan
52 {
53     public static Logger LOGGER = Logger.getLogger(RWLockMan.class.getName());
54     
55   private static RWLockMan rwLockMan;
56   public static synchronized RWLockMan getRWLockMan()
57   {
58     if (rwLockMan == null)
59       rwLockMan = new RWLockMan();
60     return rwLockMan;
61   }
62
63   protected RWLockMan()
64   {
65   }
66
67   private Object JavaDoc mutex = new Object JavaDoc();
68
69   private static class ThreadCounter
70   {
71     private Thread JavaDoc thread;
72     public Thread JavaDoc getThread() { return thread; }
73
74     public int threadCount = 0;
75
76     public ThreadCounter(Thread JavaDoc _thread)
77     {
78       this.thread = _thread;
79     }
80   }
81
82   private static class RWLockCounter
83   {
84     private RWLock rwLock;
85     public RWLock getRWLock() { return rwLock; }
86
87     public int rwLockCountRead = 0;
88     public int rwLockCountWrite = 0;
89
90     public RWLockCounter(RWLock _rwLock)
91     {
92       this.rwLock = _rwLock;
93     }
94
95     public String JavaDoc toString()
96     {
97       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
98       sb.append("RWLockCounter{");
99       sb.append(rwLock.toString());
100       sb.append(",reads=");
101       sb.append(rwLockCountRead);
102       sb.append(",writes=");
103       sb.append(rwLockCountWrite);
104       sb.append('}');
105       return sb.toString();
106     }
107
108 // public int hashCode()
109
// {
110
// return rwLock.hashCode();
111
// }
112
//
113
// public boolean equals(Object obj)
114
// {
115
// return rwLock.equals(obj);
116
// }
117

118   }
119
120   /**
121    * Key: RWLock rwLock<br/>
122    * Value: HashMap threads (HashMap key: Thread, value: ThreadCounter)
123    */

124   private HashMap JavaDoc heldLocksToThreadsMap = new HashMap JavaDoc();
125
126
127   /**
128    * Key: Thread thread<br/>
129    * Value: HashMap heldRWLocks (HashMap key: RWLock, value: RWLockCounter)
130    */

131   private HashMap JavaDoc threadsToHeldLocksMap = new HashMap JavaDoc();
132
133
134   /**
135    * Key: Thread thread<br/>
136    * Value: HashMap waitingForRWLocks (HashMap key: RWLock, value: RWLockCounter)
137    */

138   private HashMap JavaDoc waitingThreadsToLocksMap = new HashMap JavaDoc();
139
140   public static final byte MODE_READ = 120;
141   public static final byte MODE_WRITE = 121;
142
143   public static String JavaDoc modeToString(byte mode)
144   {
145     if (mode == MODE_READ)
146       return "MODE_READ";
147     else if (mode == MODE_WRITE)
148       return "MODE_WRITE";
149     else
150       throw new IllegalArgumentException JavaDoc("unknown mode: "+mode);
151   }
152
153
154   public void beginWaitForLock(RWLock rwLock, byte mode)
155   throws DeadLockException
156   {
157     try {
158       if (mode != MODE_READ && mode != MODE_WRITE)
159         throw new IllegalArgumentException JavaDoc("unknown mode!");
160
161       Thread JavaDoc currentThread = Thread.currentThread();
162
163       synchronized (mutex) {
164
165         // *** DeadLock-Prüfung ***
166

167         // Welche locks besitzen wir selbst? Dieses Set brauchen wir später...
168
HashMap JavaDoc ourHeldLocks = (HashMap JavaDoc)threadsToHeldLocksMap.get(currentThread);
169
170         // Wir sind gezwungen, auf ein Lock zu warten. Also schauen wir mal,
171
// wer es besitzt und uns somit zum warten zwingt.
172
HashMap JavaDoc threads = (HashMap JavaDoc)heldLocksToThreadsMap.get(rwLock);
173         if (threads != null) {
174
175           // Nun könnte es sein, daß wir selbst etwas besitzen, worauf diese Threads
176
// gerade warten.
177
// Also iterieren wir alle gefunden Threads und deren Warte-Locks durch
178
for (Iterator JavaDoc itThreads = threads.keySet().iterator(); itThreads.hasNext(); ) {
179             Thread JavaDoc thread = (Thread JavaDoc) itThreads.next();
180
181             if (thread != currentThread) {
182
183               // Auf welche Locks wartet dieser Thread?
184
HashMap JavaDoc waitingForRWLocks = (HashMap JavaDoc)waitingThreadsToLocksMap.get(thread);
185               if (waitingForRWLocks != null) {
186
187                 if (ourHeldLocks != null) { // wenn wir keine eigenen Locks besitzen, brauchen wir nicht prüfen
188

189                   // Nun könnte es sein, daß wir eines dieser Locks besitzen, was zu einem Deadlock führen würde.
190
for (Iterator JavaDoc itLocks = waitingForRWLocks.values().iterator(); itLocks.hasNext(); ) {
191                     RWLockCounter rwLockCounter = (RWLockCounter) itLocks.next();
192
193
194                     RWLockCounter ourHeldLockCounter = (RWLockCounter)ourHeldLocks.get(rwLockCounter.getRWLock());
195
196                     if (ourHeldLockCounter != null) {
197                       // Wenn wir selbst eine Schreibsperre auf etwas haben, auf das ein
198
// anderer wartet, von dem wir abhängig sind, dann ist das auf jeden
199
// Fall ein Dead-Lock.
200

201                       // Es ist auch ein DeadLock, wenn der andere eine Schreibsperre will, und wir eine
202
// Lese-Sperre darauf gesetzt haben.
203
if (
204                         ourHeldLockCounter.rwLockCountWrite > 0 ||
205                         rwLockCounter.rwLockCountWrite > 0
206                       )
207                         throw new DeadLockException(currentThread+": We are about to wait for lock "+rwLock+"("+modeToString(mode)+") which is held by thread "+thread+". This thread is waiting for lock "+rwLockCounter+" which is held by us: "+ourHeldLockCounter);
208
209                     } // if (ourHeldLockCounter != null) {
210

211
212                   } // for (Iterator itLocks = waitingForRWLocks.iterator(); itLocks.hasNext(); ) {
213
} // if (ourHeldLocks != null) {
214

215               } // if (waitingForRWLocks != null) {
216

217             } // if (thread != currentThread) {
218

219           } // for (Iterator itThreads = threads.keySet().iterator(); itThreads.hasNext(); ) {
220
} // if (threads != null) {
221

222         // *** / DeadLock-Prüfung ***
223

224
225         // *** wait registrieren ***
226

227         HashMap JavaDoc waitingForRWLocks = (HashMap JavaDoc)waitingThreadsToLocksMap.get(currentThread);
228         if (waitingForRWLocks == null) {
229           waitingForRWLocks = new HashMap JavaDoc();
230           waitingThreadsToLocksMap.put(currentThread, waitingForRWLocks);
231         }
232
233         RWLockCounter rwLockCounter = (RWLockCounter)waitingForRWLocks.get(rwLock);
234         if (rwLockCounter == null) {
235           rwLockCounter = new RWLockCounter(rwLock);
236           waitingForRWLocks.put(rwLock, rwLockCounter);
237         } // if (rwLockCounter == null) {
238

239         if (mode == MODE_READ)
240           rwLockCounter.rwLockCountRead++;
241         else
242           rwLockCounter.rwLockCountWrite++;
243
244         // *** / wait registrieren ***
245

246       } // synchronized (mutex) {
247

248     } catch (RuntimeException JavaDoc x) {
249         LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), x);
250       throw x;
251     } catch (Throwable JavaDoc t) {
252         LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), t);
253       throw new RuntimeException JavaDoc(t);
254     }
255   }
256
257   public void endWaitForLock(RWLock rwLock, byte mode)
258   {
259     try {
260       if (mode != MODE_READ && mode != MODE_WRITE)
261         throw new IllegalArgumentException JavaDoc("unknown mode!");
262
263       Thread JavaDoc currentThread = Thread.currentThread();
264
265       synchronized (mutex) {
266
267         HashMap JavaDoc waitingForRWLocks = (HashMap JavaDoc)waitingThreadsToLocksMap.get(currentThread);
268         if (waitingForRWLocks == null)
269           throw new IllegalStateException JavaDoc(currentThread+": No waiting locks registered for this thread! Unable to end wait for lock: "+rwLock);
270
271         RWLockCounter rwLockCounter = (RWLockCounter)waitingForRWLocks.get(rwLock);
272         if (rwLockCounter == null)
273           throw new IllegalStateException JavaDoc(currentThread+": No waiting lockCounter registered for this thread! Unable to end wait for lock: "+rwLock);
274
275
276         if (mode == MODE_READ)
277           rwLockCounter.rwLockCountRead--;
278         else
279           rwLockCounter.rwLockCountWrite--;
280
281
282         if (rwLockCounter.rwLockCountRead == 0 && rwLockCounter.rwLockCountWrite == 0) {
283           // References löschen, damit der Garbage Collector den Müll
284
// wegräumen kann.
285

286           waitingForRWLocks.remove(rwLock);
287
288           if (waitingForRWLocks.isEmpty())
289             waitingThreadsToLocksMap.remove(currentThread);
290
291         } // if (rwLockCounter.rwLockCountRead == 0 && rwLockCounter.rwLockCountWrite == 0) {
292
} // synchronized (mutex) {
293

294     } catch (RuntimeException JavaDoc x) {
295         LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), x);
296       throw x;
297     } catch (Throwable JavaDoc t) {
298       LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), t);
299       throw new RuntimeException JavaDoc(t);
300     }
301   }
302
303   public void acquireLock(RWLock rwLock, byte mode, int count)
304   {
305     try {
306       if (mode != MODE_READ && mode != MODE_WRITE)
307         throw new IllegalArgumentException JavaDoc("unknown mode!");
308
309       Thread JavaDoc currentThread = Thread.currentThread();
310
311       synchronized (mutex) {
312         HashMap JavaDoc threads = (HashMap JavaDoc)heldLocksToThreadsMap.get(rwLock);
313         if (threads == null) {
314           threads = new HashMap JavaDoc();
315           heldLocksToThreadsMap.put(rwLock, threads);
316         }
317
318         ThreadCounter threadCounter = (ThreadCounter)threads.get(currentThread);
319         if (threadCounter == null) {
320           threadCounter = new ThreadCounter(currentThread);
321           threads.put(currentThread, threadCounter);
322         } // if (threadCounter == null) {
323

324         threadCounter.threadCount += count;
325
326
327
328         HashMap JavaDoc heldLocks = (HashMap JavaDoc)threadsToHeldLocksMap.get(currentThread);
329         if (heldLocks == null) {
330           heldLocks = new HashMap JavaDoc();
331           threadsToHeldLocksMap.put(currentThread, heldLocks);
332         }
333
334         RWLockCounter rwLockCounter = (RWLockCounter)heldLocks.get(rwLock);
335         if (rwLockCounter == null) {
336           rwLockCounter = new RWLockCounter(rwLock);
337           heldLocks.put(rwLock, rwLockCounter);
338         } // if (rwLockCounter == null) {
339

340         if (mode == MODE_READ)
341           rwLockCounter.rwLockCountRead += count;
342         else
343           rwLockCounter.rwLockCountWrite += count;
344
345       } // synchronized (mutex) {
346

347     } catch (RuntimeException JavaDoc x) {
348       LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), x);
349       throw x;
350     } catch (Throwable JavaDoc t) {
351         LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), t);
352       throw new RuntimeException JavaDoc(t);
353     }
354   }
355
356   public void releaseLock(RWLock rwLock, byte mode, int count)
357   {
358     try {
359       if (mode != MODE_READ && mode != MODE_WRITE)
360         throw new IllegalArgumentException JavaDoc("unknown mode!");
361
362       Thread JavaDoc currentThread = Thread.currentThread();
363
364       synchronized (mutex) {
365
366         HashMap JavaDoc threads = (HashMap JavaDoc)heldLocksToThreadsMap.get(rwLock);
367         if (threads == null)
368           throw new IllegalStateException JavaDoc(currentThread+": No possessing threads registered for this lock! Unable to release lock: "+rwLock);
369
370         ThreadCounter threadCounter = (ThreadCounter)threads.get(currentThread);
371         if (threadCounter == null)
372           throw new IllegalStateException JavaDoc(currentThread+": No thread counter registered for this lock & current thread! Unable to release lock: "+rwLock);
373
374
375
376
377         HashMap JavaDoc heldLocks = (HashMap JavaDoc)threadsToHeldLocksMap.get(currentThread);
378         if (heldLocks == null)
379           throw new IllegalStateException JavaDoc(currentThread+": No held locks registered for this thread! Unable to release lock: "+rwLock);
380
381         RWLockCounter rwLockCounter = (RWLockCounter)heldLocks.get(rwLock);
382         if (rwLockCounter == null)
383           throw new IllegalStateException JavaDoc(currentThread+": No lock counter registered for this thread & lock! Unable to release lock: "+rwLock);
384
385
386         threadCounter.threadCount -= count;
387
388         if (mode == MODE_READ)
389           rwLockCounter.rwLockCountRead -= count;
390         else
391           rwLockCounter.rwLockCountWrite -= count;
392
393         // Müll wegräumen
394

395         if (threadCounter.threadCount == 0) {
396
397           threads.remove(currentThread);
398
399           if (threads.isEmpty())
400             heldLocksToThreadsMap.get(rwLock);
401
402         } // if (threadCounter.threadCount == 0) {
403

404         if (rwLockCounter.rwLockCountRead == 0 && rwLockCounter.rwLockCountWrite == 0) {
405
406           heldLocks.remove(rwLock);
407
408           if (heldLocks.isEmpty())
409             threadsToHeldLocksMap.remove(currentThread);
410
411         } // if (rwLockCounter.rwLockCountRead == 0 && rwLockCounter.rwLockCountWrite == 0) {
412

413       } // synchronized (mutex) {
414

415     } catch (RuntimeException JavaDoc x) {
416         LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), x);
417       throw x;
418     } catch (Throwable JavaDoc t) {
419       LOGGER.log(Level.FATAL, "Exception in thread "+Thread.currentThread(), t);
420       throw new RuntimeException JavaDoc(t);
421     }
422   }
423
424 }
Popular Tags