Mercurial > hg > blitz_condensed
comparison src/EDU/oswego/cs/dl/util/concurrent/ReentrantWriterPreferenceReadWriteLock.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3dc0c5604566 |
---|---|
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 |