Mercurial > hg > blitz_condensed
comparison src/EDU/oswego/cs/dl/util/concurrent/SyncCollection.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: SyncCollection.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 1Aug1998 dl Create public version | |
12 */ | |
13 | |
14 package EDU.oswego.cs.dl.util.concurrent; | |
15 import java.util.*; | |
16 | |
17 /** | |
18 * SyncCollections wrap Sync-based control around java.util.Collections. | |
19 * They are similar in operation to those provided | |
20 * by java.util.Collection.synchronizedCollection, but have | |
21 * several extended capabilities. | |
22 * <p> | |
23 * The Collection interface is conceptually broken into two | |
24 * parts for purposes of synchronization control. The purely inspective | |
25 * reader operations are: | |
26 * <ul> | |
27 * <li> size | |
28 * <li> isEmpty | |
29 * <li> toArray | |
30 * <li> contains | |
31 * <li> containsAll | |
32 * <li> iterator | |
33 * </ul> | |
34 * The possibly mutative writer operations (which are also | |
35 * the set of operations that are allowed to throw | |
36 * UnsupportedOperationException) are: | |
37 * <ul> | |
38 * <li> add | |
39 * <li> addAll | |
40 * <li> remove | |
41 * <li> clear | |
42 * <li> removeAll | |
43 * <li> retainAll | |
44 * </ul> | |
45 * | |
46 * <p> | |
47 * SyncCollections can be used with either Syncs or ReadWriteLocks. | |
48 * When used with | |
49 * single Syncs, the same lock is used as both the reader and writer lock. | |
50 * The SyncCollection class cannot itself guarantee that using | |
51 * a pair of read/write locks will always correctly protect objects, since | |
52 * Collection implementations are not precluded from internally | |
53 * performing hidden unprotected state changes within conceptually read-only | |
54 * operations. However, they do work with current java.util implementations. | |
55 * (Hopefully, implementations that do not provide this natural | |
56 * guarantee will be clearly documentented as such.) | |
57 * <p> | |
58 * This class provides a straight implementation of Collections interface. | |
59 * In order to conform to this interface, sync failures | |
60 * due to interruption do NOT result in InterruptedExceptions. | |
61 * Instead, upon detection of interruption, | |
62 * <ul> | |
63 * <li> All mutative operations convert the interruption to | |
64 * an UnsupportedOperationException, while also propagating | |
65 * the interrupt status of the thread. Thus, unlike normal | |
66 * java.util.Collections, SyncCollections can <em>transiently</em> | |
67 * behave as if mutative operations are not supported. | |
68 * <li> All read-only operations | |
69 * attempt to return a result even upon interruption. In some contexts, | |
70 * such results will be meaningless due to interference, but | |
71 * provide best-effort status indications that can be useful during | |
72 * recovery. The cumulative number of synchronization failures encountered | |
73 * during such operations is accessible using method | |
74 * <code>synchronizationFailures()</code>. | |
75 * Non-zero values may indicate serious program errors. | |
76 * </ul> | |
77 * <p> | |
78 * The iterator() method returns a SyncCollectionIterator with | |
79 * properties and methods that are analogous to those of SyncCollection | |
80 * itself: hasNext and next are read-only, and remove is mutative. | |
81 * These methods allow fine-grained controlled access, but do <em>NOT</em> | |
82 * preclude concurrent modifications from being interleaved with traversals, | |
83 * which may lead to ConcurrentModificationExceptions. | |
84 * However, the class also supports method <code>unprotectedIterator</code> | |
85 * that can be used in conjunction with the <code>readerSync</code> or | |
86 * <code>writerSync</code> methods to perform locked traversals. For example, | |
87 * to protect a block of reads: | |
88 * <pre> | |
89 * Sync lock = coll.readerSync(); | |
90 * try { | |
91 * lock.acquire(); | |
92 * try { | |
93 * Iterator it = coll.unprotectedIterator(); | |
94 * while (it.hasNext()) | |
95 * System.out.println(it.next()); | |
96 * } | |
97 * finally { | |
98 * lock.release(); | |
99 * } | |
100 * } | |
101 * catch (InterruptedException ex) { ... } | |
102 * </pre> | |
103 * If you need to protect blocks of writes, you must use some | |
104 * form of <em>reentrant</em> lock (for example <code>ReentrantLock</code> | |
105 * or <code>ReentrantWriterPreferenceReadWriteLock</code>) as the Sync | |
106 * for the collection in order to allow mutative methods to proceed | |
107 * while the current thread holds the lock. For example, you might | |
108 * need to hold a write lock during an initialization sequence: | |
109 * <pre> | |
110 * Collection c = new SyncCollection(new ArrayList(), | |
111 * new ReentrantWriterPreferenceReadWriteLock()); | |
112 * // ... | |
113 * c.writeLock().acquire(); | |
114 * try { | |
115 * for (...) { | |
116 * Object x = someStream.readObject(); | |
117 * c.add(x); // would block if writeLock not reentrant | |
118 * } | |
119 * } | |
120 * catch (IOException iox) { | |
121 * ... | |
122 * } | |
123 * finally { | |
124 * c.writeLock().release(); | |
125 * } | |
126 * catch (InterruptedException ex) { ... } | |
127 * </pre> | |
128 * <p> | |
129 * (It would normally be better practice here to not make the | |
130 * collection accessible until initialization is complete.) | |
131 * <p> | |
132 * This class does not specifically support use of | |
133 * timed synchronization through the attempt method. However, | |
134 * you can obtain this effect via | |
135 * the TimeoutSync class. For example: | |
136 * <pre> | |
137 * Mutex lock = new Mutex(); | |
138 * TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts | |
139 * Collection c = new SyncCollection(new HashSet(), timedlock); | |
140 * </pre> | |
141 * <p> | |
142 * The same can be done with read-write locks: | |
143 * <pre> | |
144 * ReadWriteLock rwl = new WriterPreferenceReadWriteLock(); | |
145 * Sync rlock = new TimeoutSync(rwl.readLock(), 100); | |
146 * Sync wlock = new TimeoutSync(rwl.writeLock(), 100); | |
147 * Collection c = new SyncCollection(new HashSet(), rlock, wlock); | |
148 * </pre> | |
149 * <p> | |
150 * In addition to synchronization control, SyncCollections | |
151 * may be useful in any context requiring before/after methods | |
152 * surrounding collections. For example, you can use ObservableSync | |
153 * to arrange notifications on method calls to collections, as in: | |
154 * <pre> | |
155 * class X { | |
156 * Collection c; | |
157 * | |
158 * static class CollectionObserver implements ObservableSync.SyncObserver { | |
159 * public void onAcquire(Object arg) { | |
160 * Collection coll = (Collection) arg; | |
161 * System.out.println("Starting operation on" + coll); | |
162 * // Other plausible responses include performing integrity | |
163 * // checks on the collection, updating displays, etc | |
164 * } | |
165 * public void onRelease(Object arg) { | |
166 * Collection coll = (Collection) arg; | |
167 * System.out.println("Finished operation on" + coll); | |
168 * } | |
169 * } | |
170 * | |
171 * X() { | |
172 * ObservableSync s = new ObservableSync(); | |
173 * c = new SyncCollection(new HashSet(), s); | |
174 * s.setNotificationArgument(c); | |
175 * CollectionObserver obs = new CollectionObserver(); | |
176 * s.attach(obs); | |
177 * } | |
178 * ... | |
179 * } | |
180 * </pre> | |
181 * | |
182 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] | |
183 * @see LayeredSync | |
184 * @see TimeoutSync | |
185 **/ | |
186 | |
187 | |
188 public class SyncCollection implements Collection { | |
189 protected final Collection c_; // Backing Collection | |
190 protected final Sync rd_; // sync for read-only methods | |
191 protected final Sync wr_; // sync for mutative methods | |
192 | |
193 protected final SynchronizedLong syncFailures_ = new SynchronizedLong(0); | |
194 | |
195 /** | |
196 * Create a new SyncCollection protecting the given collection, | |
197 * and using the given sync to control both reader and writer methods. | |
198 * Common, reasonable choices for the sync argument include | |
199 * Mutex, ReentrantLock, and Semaphores initialized to 1. | |
200 * <p> | |
201 * <b>Sample Usage</b> | |
202 * <pre> | |
203 * Collection c = new SyncCollection(new ArrayList(), new Mutex()); | |
204 * </pre> | |
205 **/ | |
206 public SyncCollection(Collection collection, Sync sync) { | |
207 this (collection, sync, sync); | |
208 } | |
209 | |
210 | |
211 /** | |
212 * Create a new SyncCollection protecting the given collection, | |
213 * and using the given ReadWriteLock to control reader and writer methods. | |
214 * <p> | |
215 * <b>Sample Usage</b> | |
216 * <pre> | |
217 * Collection c = new SyncCollection(new HashSet(), | |
218 * new WriterPreferenceReadWriteLock()); | |
219 * </pre> | |
220 **/ | |
221 public SyncCollection(Collection collection, ReadWriteLock rwl) { | |
222 this (collection, rwl.readLock(), rwl.writeLock()); | |
223 } | |
224 | |
225 /** | |
226 * Create a new SyncCollection protecting the given collection, | |
227 * and using the given pair of locks to control reader and writer methods. | |
228 **/ | |
229 public SyncCollection(Collection collection, Sync readLock, Sync writeLock) { | |
230 c_ = collection; | |
231 rd_ = readLock; | |
232 wr_ = writeLock; | |
233 } | |
234 | |
235 /** | |
236 * Return the Sync object managing read-only operations | |
237 **/ | |
238 | |
239 public Sync readerSync() { | |
240 return rd_; | |
241 } | |
242 | |
243 /** | |
244 * Return the Sync object managing mutative operations | |
245 **/ | |
246 | |
247 public Sync writerSync() { | |
248 return wr_; | |
249 } | |
250 | |
251 /** | |
252 * Return the number of synchronization failures for read-only operations | |
253 **/ | |
254 public long syncFailures() { | |
255 return syncFailures_.get(); | |
256 } | |
257 | |
258 | |
259 /** Try to acquire sync before a reader operation; record failure **/ | |
260 protected boolean beforeRead() { | |
261 try { | |
262 rd_.acquire(); | |
263 return false; | |
264 } | |
265 catch (InterruptedException ex) { | |
266 syncFailures_.increment(); | |
267 return true; | |
268 } | |
269 } | |
270 | |
271 /** Clean up after a reader operation **/ | |
272 protected void afterRead(boolean wasInterrupted) { | |
273 if (wasInterrupted) { | |
274 Thread.currentThread().interrupt(); | |
275 } | |
276 else | |
277 rd_.release(); | |
278 } | |
279 | |
280 | |
281 | |
282 public int size() { | |
283 boolean wasInterrupted = beforeRead(); | |
284 try { | |
285 return c_.size(); | |
286 } | |
287 finally { | |
288 afterRead(wasInterrupted); | |
289 } | |
290 } | |
291 | |
292 public boolean isEmpty() { | |
293 boolean wasInterrupted = beforeRead(); | |
294 try { | |
295 return c_.isEmpty(); | |
296 } | |
297 finally { | |
298 afterRead(wasInterrupted); | |
299 } | |
300 } | |
301 | |
302 public boolean contains(Object o) { | |
303 boolean wasInterrupted = beforeRead(); | |
304 try { | |
305 return c_.contains(o); | |
306 } | |
307 finally { | |
308 afterRead(wasInterrupted); | |
309 } | |
310 } | |
311 | |
312 public Object[] toArray() { | |
313 boolean wasInterrupted = beforeRead(); | |
314 try { | |
315 return c_.toArray(); | |
316 } | |
317 finally { | |
318 afterRead(wasInterrupted); | |
319 } | |
320 } | |
321 | |
322 public Object[] toArray(Object[] a) { | |
323 boolean wasInterrupted = beforeRead(); | |
324 try { | |
325 return c_.toArray(a); | |
326 } | |
327 finally { | |
328 afterRead(wasInterrupted); | |
329 } | |
330 } | |
331 | |
332 public boolean containsAll(Collection coll) { | |
333 boolean wasInterrupted = beforeRead(); | |
334 try { | |
335 return c_.containsAll(coll); | |
336 } | |
337 finally { | |
338 afterRead(wasInterrupted); | |
339 } | |
340 } | |
341 | |
342 | |
343 public boolean add(Object o) { | |
344 try { | |
345 wr_.acquire(); | |
346 try { | |
347 return c_.add(o); | |
348 } | |
349 finally { | |
350 wr_.release(); | |
351 } | |
352 } | |
353 catch (InterruptedException ex) { | |
354 Thread.currentThread().interrupt(); | |
355 throw new UnsupportedOperationException(); | |
356 } | |
357 } | |
358 | |
359 public boolean remove(Object o) { | |
360 try { | |
361 wr_.acquire(); | |
362 try { | |
363 return c_.remove(o); | |
364 } | |
365 finally { | |
366 wr_.release(); | |
367 } | |
368 } | |
369 catch (InterruptedException ex) { | |
370 Thread.currentThread().interrupt(); | |
371 throw new UnsupportedOperationException(); | |
372 } | |
373 } | |
374 | |
375 public boolean addAll(Collection coll) { | |
376 try { | |
377 wr_.acquire(); | |
378 try { | |
379 return c_.addAll(coll); | |
380 } | |
381 finally { | |
382 wr_.release(); | |
383 } | |
384 } | |
385 catch (InterruptedException ex) { | |
386 Thread.currentThread().interrupt(); | |
387 throw new UnsupportedOperationException(); | |
388 } | |
389 } | |
390 | |
391 public boolean removeAll(Collection coll) { | |
392 try { | |
393 wr_.acquire(); | |
394 try { | |
395 return c_.removeAll(coll); | |
396 } | |
397 finally { | |
398 wr_.release(); | |
399 } | |
400 } | |
401 catch (InterruptedException ex) { | |
402 Thread.currentThread().interrupt(); | |
403 throw new UnsupportedOperationException(); | |
404 } | |
405 } | |
406 | |
407 | |
408 public boolean retainAll(Collection coll) { | |
409 try { | |
410 wr_.acquire(); | |
411 try { | |
412 return c_.retainAll(coll); | |
413 } | |
414 finally { | |
415 wr_.release(); | |
416 } | |
417 } | |
418 catch (InterruptedException ex) { | |
419 Thread.currentThread().interrupt(); | |
420 throw new UnsupportedOperationException(); | |
421 } | |
422 } | |
423 | |
424 | |
425 public void clear() { | |
426 try { | |
427 wr_.acquire(); | |
428 try { | |
429 c_.clear(); | |
430 } | |
431 finally { | |
432 wr_.release(); | |
433 } | |
434 } | |
435 catch (InterruptedException ex) { | |
436 Thread.currentThread().interrupt(); | |
437 throw new UnsupportedOperationException(); | |
438 } | |
439 } | |
440 | |
441 | |
442 /** Return the base iterator of the underlying collection **/ | |
443 public Iterator unprotectedIterator() { | |
444 boolean wasInterrupted = beforeRead(); | |
445 try { | |
446 return c_.iterator(); | |
447 } | |
448 finally { | |
449 afterRead(wasInterrupted); | |
450 } | |
451 } | |
452 | |
453 public Iterator iterator() { | |
454 boolean wasInterrupted = beforeRead(); | |
455 try { | |
456 return new SyncCollectionIterator(c_.iterator()); | |
457 } | |
458 finally { | |
459 afterRead(wasInterrupted); | |
460 } | |
461 } | |
462 | |
463 public class SyncCollectionIterator implements Iterator { | |
464 protected final Iterator baseIterator_; | |
465 | |
466 SyncCollectionIterator(Iterator baseIterator) { | |
467 baseIterator_ = baseIterator; | |
468 } | |
469 | |
470 public boolean hasNext() { | |
471 boolean wasInterrupted = beforeRead(); | |
472 try { | |
473 return baseIterator_.hasNext(); | |
474 } | |
475 finally { | |
476 afterRead(wasInterrupted); | |
477 } | |
478 } | |
479 | |
480 public Object next() { | |
481 boolean wasInterrupted = beforeRead(); | |
482 try { | |
483 return baseIterator_.next(); | |
484 } | |
485 finally { | |
486 afterRead(wasInterrupted); | |
487 } | |
488 } | |
489 | |
490 public void remove() { | |
491 try { | |
492 wr_.acquire(); | |
493 try { | |
494 baseIterator_.remove(); | |
495 } | |
496 finally { | |
497 wr_.release(); | |
498 } | |
499 } | |
500 catch (InterruptedException ex) { | |
501 Thread.currentThread().interrupt(); | |
502 throw new UnsupportedOperationException(); | |
503 } | |
504 } | |
505 | |
506 } | |
507 } | |
508 | |
509 |