001: /*
002: File: SyncMap.java
003:
004: Originally written by Doug Lea and released into the public domain.
005: This may be used for any purposes whatsoever without acknowledgment.
006: Thanks for the assistance and support of Sun Microsystems Labs,
007: and everyone contributing, testing, and using this code.
008:
009: History:
010: Date Who What
011: 1Aug1998 dl Create public version
012: */
013:
014: package EDU.oswego.cs.dl.util.concurrent;
015:
016: import java.util.*;
017:
018: /**
019: * SyncMaps wrap Sync-based control around java.util.Maps.
020: * They operate in the same way as SyncCollection.
021: * <p>
022: * Reader operations are
023: * <ul>
024: * <li> size
025: * <li> isEmpty
026: * <li> get
027: * <li> containsKey
028: * <li> containsValue
029: * <li> keySet
030: * <li> entrySet
031: * <li> values
032: * </ul>
033: * Writer operations are:
034: * <ul>
035: * <li> put
036: * <li> putAll
037: * <li> remove
038: * <li> clear
039: * </ul>
040: *
041: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
042: * @see SyncCollection
043: **/
044:
045: public class SyncMap implements Map {
046: protected final Map c_; // Backing Map
047: protected final Sync rd_; // sync for read-only methods
048: protected final Sync wr_; // sync for mutative methods
049:
050: protected final SynchronizedLong syncFailures_ = new SynchronizedLong(
051: 0);
052:
053: /**
054: * Create a new SyncMap protecting the given map,
055: * and using the given sync to control both reader and writer methods.
056: * Common, reasonable choices for the sync argument include
057: * Mutex, ReentrantLock, and Semaphores initialized to 1.
058: **/
059: public SyncMap(Map map, Sync sync) {
060: this (map, sync, sync);
061: }
062:
063: /**
064: * Create a new SyncMap protecting the given map,
065: * and using the given ReadWriteLock to control reader and writer methods.
066: **/
067: public SyncMap(Map map, ReadWriteLock rwl) {
068: this (map, rwl.readLock(), rwl.writeLock());
069: }
070:
071: /**
072: * Create a new SyncMap protecting the given map,
073: * and using the given pair of locks to control reader and writer methods.
074: **/
075: public SyncMap(Map map, Sync readLock, Sync writeLock) {
076: c_ = map;
077: rd_ = readLock;
078: wr_ = writeLock;
079: }
080:
081: /**
082: * Return the Sync object managing read-only operations
083: **/
084:
085: public Sync readerSync() {
086: return rd_;
087: }
088:
089: /**
090: * Return the Sync object managing mutative operations
091: **/
092:
093: public Sync writerSync() {
094: return wr_;
095: }
096:
097: /**
098: * Return the number of synchronization failures for read-only operations
099: **/
100: public long syncFailures() {
101: return syncFailures_.get();
102: }
103:
104: /** Try to acquire sync before a reader operation; record failure **/
105: protected boolean beforeRead() {
106: try {
107: rd_.acquire();
108: return false;
109: } catch (InterruptedException ex) {
110: syncFailures_.increment();
111: return true;
112: }
113: }
114:
115: /** Clean up after a reader operation **/
116: protected void afterRead(boolean wasInterrupted) {
117: if (wasInterrupted) {
118: Thread.currentThread().interrupt();
119: } else
120: rd_.release();
121: }
122:
123: public int hashCode() {
124: boolean wasInterrupted = beforeRead();
125: try {
126: return c_.hashCode();
127: } finally {
128: afterRead(wasInterrupted);
129: }
130: }
131:
132: public boolean equals(Object o) {
133: boolean wasInterrupted = beforeRead();
134: try {
135: return c_.equals(o);
136: } finally {
137: afterRead(wasInterrupted);
138: }
139: }
140:
141: public int size() {
142: boolean wasInterrupted = beforeRead();
143: try {
144: return c_.size();
145: } finally {
146: afterRead(wasInterrupted);
147: }
148: }
149:
150: public boolean isEmpty() {
151: boolean wasInterrupted = beforeRead();
152: try {
153: return c_.isEmpty();
154: } finally {
155: afterRead(wasInterrupted);
156: }
157: }
158:
159: public boolean containsKey(Object o) {
160: boolean wasInterrupted = beforeRead();
161: try {
162: return c_.containsKey(o);
163: } finally {
164: afterRead(wasInterrupted);
165: }
166: }
167:
168: public boolean containsValue(Object o) {
169: boolean wasInterrupted = beforeRead();
170: try {
171: return c_.containsValue(o);
172: } finally {
173: afterRead(wasInterrupted);
174: }
175: }
176:
177: public Object get(Object key) {
178: boolean wasInterrupted = beforeRead();
179: try {
180: return c_.get(key);
181: } finally {
182: afterRead(wasInterrupted);
183: }
184: }
185:
186: public Object put(Object key, Object value) {
187: try {
188: wr_.acquire();
189: try {
190: return c_.put(key, value);
191: } finally {
192: wr_.release();
193: }
194: } catch (InterruptedException ex) {
195: Thread.currentThread().interrupt();
196: throw new UnsupportedOperationException();
197: }
198: }
199:
200: public Object remove(Object key) {
201: try {
202: wr_.acquire();
203: try {
204: return c_.remove(key);
205: } finally {
206: wr_.release();
207: }
208: } catch (InterruptedException ex) {
209: Thread.currentThread().interrupt();
210: throw new UnsupportedOperationException();
211: }
212: }
213:
214: public void putAll(Map coll) {
215: try {
216: wr_.acquire();
217: try {
218: c_.putAll(coll);
219: } finally {
220: wr_.release();
221: }
222: } catch (InterruptedException ex) {
223: Thread.currentThread().interrupt();
224: throw new UnsupportedOperationException();
225: }
226: }
227:
228: public void clear() {
229: try {
230: wr_.acquire();
231: try {
232: c_.clear();
233: } finally {
234: wr_.release();
235: }
236: } catch (InterruptedException ex) {
237: Thread.currentThread().interrupt();
238: throw new UnsupportedOperationException();
239: }
240: }
241:
242: private transient Set keySet_ = null;
243: private transient Set entrySet_ = null;
244: private transient Collection values_ = null;
245:
246: public Set keySet() {
247: boolean wasInterrupted = beforeRead();
248: try {
249: if (keySet_ == null)
250: keySet_ = new SyncSet(c_.keySet(), rd_, wr_);
251: return keySet_;
252: } finally {
253: afterRead(wasInterrupted);
254: }
255: }
256:
257: public Set entrySet() {
258: boolean wasInterrupted = beforeRead();
259: try {
260: if (entrySet_ == null)
261: entrySet_ = new SyncSet(c_.entrySet(), rd_, wr_);
262: return entrySet_;
263: } finally {
264: afterRead(wasInterrupted);
265: }
266: }
267:
268: public Collection values() {
269: boolean wasInterrupted = beforeRead();
270: try {
271: if (values_ == null)
272: values_ = new SyncCollection(c_.values(), rd_, wr_);
273: return values_;
274: } finally {
275: afterRead(wasInterrupted);
276: }
277: }
278:
279: }
|