Code - Class EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock


1 /*
2   File: ReentrantWriterPreferenceReadWriteLock.java
3
4   Originally written by Doug Lea and released into the public domain.
5   This may be used for any purposes whatsoever without acknowledgment.
6   Thanks for the assistance and support of Sun Microsystems Labs,
7   and everyone contributing, testing, and using this code.
8
9   History:
10   Date Who What
11   26aug1998 dl Create public version
12    7sep2000 dl Readers are now also reentrant
13   19jan2001 dl Allow read->write upgrades if the only reader
14   10dec2002 dl Throw IllegalStateException on extra release
15 */

16
17 package EDU.oswego.cs.dl.util.concurrent;
18 import java.util.*;
19
20 /**
21  * A writer-preference ReadWriteLock that allows both readers and
22  * writers to reacquire
23  * read or write locks in the style of a ReentrantLock.
24  * Readers are not allowed until all write locks held by
25  * the writing thread have been released.
26  * Among other applications, reentrancy can be useful when
27  * write locks are held during calls or callbacks to methods that perform
28  * reads under read locks.
29  * <p>
30  * <b>Sample usage</b>. Here is a code sketch showing how to exploit
31  * reentrancy to perform lock downgrading after updating a cache:
32  * <pre>
33  * class CachedData {
34  * Object data;
35  * volatile boolean cacheValid;
36  * ReentrantWriterPreferenceReadWriteLock rwl = ...
37  *
38  * void processCachedData() {
39  * rwl.readLock().acquire();
40  * if (!cacheValid) {
41  *
42  * // upgrade lock:
43  * rwl.readLock().release(); // must release first to obtain writelock
44  * rwl.writeLock().acquire();
45  * if (!cacheValid) { // recheck
46  * data = ...
47  * cacheValid = true;
48  * }
49  * // downgrade lock
50  * rwl.readLock().acquire(); // reacquire read without giving up lock
51  * rwl.writeLock().release(); // release write, still hold read
52  * }
53  *
54  * use(data);
55  * rwl.readLock().release();
56  * }
57  * }
58  * </pre>
59  *
60  *
61  * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
62  * @see ReentrantLock
63  **/

64
65 public class ReentrantWriterPreferenceReadWriteLock extends WriterPreferenceReadWriteLock {
66
67   /** Number of acquires on write lock by activeWriter_ thread **/
68   protected long writeHolds_ = 0;
69
70   /** Number of acquires on read lock by any reader thread **/
71   protected HashMap readers_ = new HashMap();
72
73   /** cache/reuse the special Integer value one to speed up readlocks **/
74   protected static final Integer IONE = new Integer(1);
75
76
77   protected boolean allowReader() {
78     return (activeWriter_ == null && waitingWriters_ == 0) ||
79       activeWriter_ == Thread.currentThread();
80   }
81
82   protected synchronized boolean startRead() {
83     Thread t = Thread.currentThread();
84     Object c = readers_.get(t);
85     if (c != null) { // already held -- just increment hold count
86
readers_.put(t, new Integer(((Integer)(c)).intValue()+1));
87       ++activeReaders_;
88       return true;
89     }
90     else if (allowReader()) {
91       readers_.put(t, IONE);
92       ++activeReaders_;
93       return true;
94     }
95     else
96       return false;
97   }
98
99   protected synchronized boolean startWrite() {
100     if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
101
++writeHolds_;
102       return true;
103     }
104     else if (writeHolds_ == 0) {
105       if (activeReaders_ == 0 ||
106           (readers_.size() == 1 &&
107            readers_.get(Thread.currentThread()) != null)) {
108         activeWriter_ = Thread.currentThread();
109         writeHolds_ = 1;
110         return true;
111       }
112       else
113         return false;
114     }
115     else
116       return false;
117   }
118
119
120   protected synchronized Signaller endRead() {
121     Thread t = Thread.currentThread();
122     Object c = readers_.get(t);
123     if (c == null)
124       throw new IllegalStateException();
125     --activeReaders_;
126     if (c != IONE) { // more than one hold; decrement count
127
int h = ((Integer)(c)).intValue()-1;
128       Integer ih = (h == 1)? IONE : new Integer(h);
129       readers_.put(t, ih);
130       return null;
131     }
132     else {
133       readers_.remove(t);
134     
135       if (writeHolds_ > 0) // a write lock is still held by current thread
136
return null;
137       else if (activeReaders_ == 0 && waitingWriters_ > 0)
138         return writerLock_;
139       else
140         return null;
141     }
142   }
143
144   protected synchronized Signaller endWrite() {
145     --writeHolds_;
146     if (writeHolds_ > 0) // still being held
147
return null;
148     else {
149       activeWriter_ = null;
150       if (waitingReaders_ > 0 && allowReader())
151         return readerLock_;
152       else if (waitingWriters_ > 0)
153         return writerLock_;
154       else
155         return null;
156     }
157   }
158
159 }
160
161

Java API By Example, From Geeks To Geeks. | Conditions of Use | About Us © 2002 - 2005, KickJava.com, or its affiliates