Class SyncCollection

  • All Implemented Interfaces:
    java.lang.Iterable, java.util.Collection
    Direct Known Subclasses:
    SyncList, SyncSet

    public class SyncCollection
    extends java.lang.Object
    implements java.util.Collection
    SyncCollections wrap Sync-based control around java.util.Collections. They are similar in operation to those provided by java.util.Collection.synchronizedCollection, but have several extended capabilities.

    The Collection interface is conceptually broken into two parts for purposes of synchronization control. The purely inspective reader operations are:

    • size
    • isEmpty
    • toArray
    • contains
    • containsAll
    • iterator
    The possibly mutative writer operations (which are also the set of operations that are allowed to throw UnsupportedOperationException) are:
    • add
    • addAll
    • remove
    • clear
    • removeAll
    • retainAll

    SyncCollections can be used with either Syncs or ReadWriteLocks. When used with single Syncs, the same lock is used as both the reader and writer lock. The SyncCollection class cannot itself guarantee that using a pair of read/write locks will always correctly protect objects, since Collection implementations are not precluded from internally performing hidden unprotected state changes within conceptually read-only operations. However, they do work with current java.util implementations. (Hopefully, implementations that do not provide this natural guarantee will be clearly documentented as such.)

    This class provides a straight implementation of Collections interface. In order to conform to this interface, sync failures due to interruption do NOT result in InterruptedExceptions. Instead, upon detection of interruption,

    • All mutative operations convert the interruption to an UnsupportedOperationException, while also propagating the interrupt status of the thread. Thus, unlike normal java.util.Collections, SyncCollections can transiently behave as if mutative operations are not supported.
    • All read-only operations attempt to return a result even upon interruption. In some contexts, such results will be meaningless due to interference, but provide best-effort status indications that can be useful during recovery. The cumulative number of synchronization failures encountered during such operations is accessible using method synchronizationFailures(). Non-zero values may indicate serious program errors.

    The iterator() method returns a SyncCollectionIterator with properties and methods that are analogous to those of SyncCollection itself: hasNext and next are read-only, and remove is mutative. These methods allow fine-grained controlled access, but do NOT preclude concurrent modifications from being interleaved with traversals, which may lead to ConcurrentModificationExceptions. However, the class also supports method unprotectedIterator that can be used in conjunction with the readerSync or writerSync methods to perform locked traversals. For example, to protect a block of reads:

        Sync lock = coll.readerSync();
        try {
          lock.acquire();
          try {
            Iterator it = coll.unprotectedIterator();
            while (it.hasNext()) 
              System.out.println(it.next());
          }
          finally {
            lock.release();
          }
       }
       catch (InterruptedException ex) { ... }
     
    If you need to protect blocks of writes, you must use some form of reentrant lock (for example ReentrantLock or ReentrantWriterPreferenceReadWriteLock) as the Sync for the collection in order to allow mutative methods to proceed while the current thread holds the lock. For example, you might need to hold a write lock during an initialization sequence:
       Collection c = new SyncCollection(new ArrayList(), 
                                         new ReentrantWriterPreferenceReadWriteLock());
       // ...
       c.writeLock().acquire();
       try {
         for (...) {
           Object x = someStream.readObject();
           c.add(x); // would block if writeLock not reentrant
         }
       }
       catch (IOException iox) {
         ...
       }
       finally {
         c.writeLock().release();
       }
       catch (InterruptedException ex) { ... }
     

    (It would normally be better practice here to not make the collection accessible until initialization is complete.)

    This class does not specifically support use of timed synchronization through the attempt method. However, you can obtain this effect via the TimeoutSync class. For example:

     Mutex lock = new Mutex();
     TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts
     Collection c = new SyncCollection(new HashSet(), timedlock);
     

    The same can be done with read-write locks:

     ReadWriteLock rwl = new WriterPreferenceReadWriteLock();
     Sync rlock = new TimeoutSync(rwl.readLock(), 100);
     Sync wlock = new TimeoutSync(rwl.writeLock(), 100);
     Collection c = new SyncCollection(new HashSet(), rlock, wlock);
     

    In addition to synchronization control, SyncCollections may be useful in any context requiring before/after methods surrounding collections. For example, you can use ObservableSync to arrange notifications on method calls to collections, as in:

     class X {
       Collection c;
    
       static class CollectionObserver implements ObservableSync.SyncObserver {
         public void onAcquire(Object arg) {
           Collection coll = (Collection) arg;
           System.out.println("Starting operation on" + coll);
           // Other plausible responses include performing integrity
           //   checks on the collection, updating displays, etc
         }
         public void onRelease(Object arg) {
           Collection coll = (Collection) arg;
           System.out.println("Finished operation on" + coll);
         }
       }
    
       X() {
         ObservableSync s = new ObservableSync();
         c = new SyncCollection(new HashSet(), s);
         s.setNotificationArgument(c);
         CollectionObserver obs = new CollectionObserver();
         s.attach(obs);
       }
       ...
     }
     

    [ Introduction to this package. ]

    See Also:
    LayeredSync, TimeoutSync
    • Constructor Summary

      Constructors 
      Constructor Description
      SyncCollection​(java.util.Collection collection, ReadWriteLock rwl)
      Create a new SyncCollection protecting the given collection, and using the given ReadWriteLock to control reader and writer methods.
      SyncCollection​(java.util.Collection collection, Sync sync)
      Create a new SyncCollection protecting the given collection, and using the given sync to control both reader and writer methods.
      SyncCollection​(java.util.Collection collection, Sync readLock, Sync writeLock)
      Create a new SyncCollection protecting the given collection, and using the given pair of locks to control reader and writer methods.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      boolean add​(java.lang.Object o)  
      boolean addAll​(java.util.Collection coll)  
      protected void afterRead​(boolean wasInterrupted)
      Clean up after a reader operation
      protected boolean beforeRead()
      Try to acquire sync before a reader operation; record failure
      void clear()  
      boolean contains​(java.lang.Object o)  
      boolean containsAll​(java.util.Collection coll)  
      boolean isEmpty()  
      java.util.Iterator iterator()  
      Sync readerSync()
      Return the Sync object managing read-only operations
      boolean remove​(java.lang.Object o)  
      boolean removeAll​(java.util.Collection coll)  
      boolean retainAll​(java.util.Collection coll)  
      int size()  
      long syncFailures()
      Return the number of synchronization failures for read-only operations
      java.lang.Object[] toArray()  
      java.lang.Object[] toArray​(java.lang.Object[] a)  
      java.util.Iterator unprotectedIterator()
      Return the base iterator of the underlying collection
      Sync writerSync()
      Return the Sync object managing mutative operations
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • Methods inherited from interface java.util.Collection

        equals, hashCode, parallelStream, removeIf, spliterator, stream, toArray
      • Methods inherited from interface java.lang.Iterable

        forEach
    • Field Detail

      • c_

        protected final java.util.Collection c_
      • rd_

        protected final Sync rd_
      • wr_

        protected final Sync wr_
    • Constructor Detail

      • SyncCollection

        public SyncCollection​(java.util.Collection collection,
                              Sync sync)
        Create a new SyncCollection protecting the given collection, and using the given sync to control both reader and writer methods. Common, reasonable choices for the sync argument include Mutex, ReentrantLock, and Semaphores initialized to 1.

        Sample Usage

         Collection c = new SyncCollection(new ArrayList(), new Mutex()); 
         
      • SyncCollection

        public SyncCollection​(java.util.Collection collection,
                              ReadWriteLock rwl)
        Create a new SyncCollection protecting the given collection, and using the given ReadWriteLock to control reader and writer methods.

        Sample Usage

         Collection c = new SyncCollection(new HashSet(), 
                                           new WriterPreferenceReadWriteLock());
         
      • SyncCollection

        public SyncCollection​(java.util.Collection collection,
                              Sync readLock,
                              Sync writeLock)
        Create a new SyncCollection protecting the given collection, and using the given pair of locks to control reader and writer methods.
    • Method Detail

      • readerSync

        public Sync readerSync()
        Return the Sync object managing read-only operations
      • writerSync

        public Sync writerSync()
        Return the Sync object managing mutative operations
      • syncFailures

        public long syncFailures()
        Return the number of synchronization failures for read-only operations
      • beforeRead

        protected boolean beforeRead()
        Try to acquire sync before a reader operation; record failure
      • afterRead

        protected void afterRead​(boolean wasInterrupted)
        Clean up after a reader operation
      • size

        public int size()
        Specified by:
        size in interface java.util.Collection
      • isEmpty

        public boolean isEmpty()
        Specified by:
        isEmpty in interface java.util.Collection
      • contains

        public boolean contains​(java.lang.Object o)
        Specified by:
        contains in interface java.util.Collection
      • toArray

        public java.lang.Object[] toArray()
        Specified by:
        toArray in interface java.util.Collection
      • toArray

        public java.lang.Object[] toArray​(java.lang.Object[] a)
        Specified by:
        toArray in interface java.util.Collection
      • containsAll

        public boolean containsAll​(java.util.Collection coll)
        Specified by:
        containsAll in interface java.util.Collection
      • add

        public boolean add​(java.lang.Object o)
        Specified by:
        add in interface java.util.Collection
      • remove

        public boolean remove​(java.lang.Object o)
        Specified by:
        remove in interface java.util.Collection
      • addAll

        public boolean addAll​(java.util.Collection coll)
        Specified by:
        addAll in interface java.util.Collection
      • removeAll

        public boolean removeAll​(java.util.Collection coll)
        Specified by:
        removeAll in interface java.util.Collection
      • retainAll

        public boolean retainAll​(java.util.Collection coll)
        Specified by:
        retainAll in interface java.util.Collection
      • clear

        public void clear()
        Specified by:
        clear in interface java.util.Collection
      • unprotectedIterator

        public java.util.Iterator unprotectedIterator()
        Return the base iterator of the underlying collection
      • iterator

        public java.util.Iterator iterator()
        Specified by:
        iterator in interface java.util.Collection
        Specified by:
        iterator in interface java.lang.Iterable