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