Class SynchronizedVariable

  • All Implemented Interfaces:
    java.util.concurrent.Executor
    Direct Known Subclasses:
    SynchronizedBoolean

    public class SynchronizedVariable
    extends java.lang.Object
    implements java.util.concurrent.Executor
    Base class for simple, small classes maintaining single values that are always accessed and updated under synchronization. Since defining them for only some types seemed too arbitrary, they exist for all basic types, although it is hard to imagine uses for some.

    These classes mainly exist so that you do not have to go to the trouble of writing your own miscellaneous classes and methods in situations including:

    • When you need or want to offload an instance variable to use its own synchronization lock. When these objects are used to replace instance variables, they should almost always be declared as final. This helps avoid the need to synchronize just to obtain the reference to the synchronized variable itself.
    • When you need methods such as set, commit, or swap. Note however that the synchronization for these variables is independent of any other synchronization perfromed using other locks. So, they are not normally useful when accesses and updates among variables must be coordinated. For example, it would normally be a bad idea to make a Point class out of two SynchronizedInts, even those sharing a lock.
    • When defining static variables. It almost always works out better to rely on synchronization internal to these objects, rather than class locks.

    While they cannot, by nature, share much code, all of these classes work in the same way.

    Construction
    Synchronized variables are always constructed holding an initial value of the associated type. Constructors also establish the lock to use for all methods:

    • By default, each variable uses itself as the synchronization lock. This is the most common choice in the most common usage contexts in which SynchronizedVariables are used to split off synchronization locks for independent attributes of a class.
    • You can specify any other Object to use as the synchronization lock. This allows you to use various forms of `slave synchronization'. For example, a variable that is always associated with a particular object can use that object's lock.

    Update methods
    Each class supports several kinds of update methods:

    • A set method that sets to a new value and returns previous value. For example, for a SynchronizedBoolean b, boolean old = b.set(true) performs a test-and-set.

    • A commit method that sets to new value only if currently holding a given value.

      For example, here is a class that uses an optimistic update loop to recompute a count variable represented as a SynchronizedInt.

       class X {
       private final SynchronizedInt count = new SynchronizedInt(0);
      
       static final int MAX_RETRIES = 1000;
      
       public boolean recomputeCount() throws InterruptedException {
       for (int i = 0; i < MAX_RETRIES; ++i) {
       int current = count.get();
       int next = compute(current);
       if (count.commit(current, next))
       return true;
       else if (Thread.interrupted())
       throw new InterruptedException();
       }
       return false;
       }
       int compute(int l) { ... some kind of computation ... }
       }
       

    • A swap method that atomically swaps with another object of the same class using a deadlock-avoidance strategy.

    • Update-in-place methods appropriate to the type. All numerical types support:
      • add(x) (equivalent to return value += x)
      • subtract(x) (equivalent to return value -= x)
      • multiply(x) (equivalent to return value *= x)
      • divide(x) (equivalent to return value /= x)
      Integral types also support:
      • increment() (equivalent to return ++value)
      • decrement() (equivalent to return --value)
      Boolean types support:
      • or(x) (equivalent to return value |= x)
      • and(x) (equivalent to return value &= x)
      • xor(x) (equivalent to return value ^= x)
      • complement() (equivalent to return x = !x)
      These cover most, but not all of the possible operators in Java. You can add more compute-and-set methods in subclasses. This is often a good way to avoid the need for ad-hoc synchronized blocks surrounding expressions.

    Guarded methods
    All Waitable subclasses provide notifications on every value update, and support guarded methods of the form whenpredicate, that wait until the predicate hold, then optionally run any Runnable action within the lock, and then return. All types support:

    • whenEqual(value, action)
    • whenNotEqual(value, action)
    (If the action argument is null, these return immediately after the predicate holds.) Numerical types also support
    • whenLess(value, action)
    • whenLessEqual(value, action)
    • whenGreater(value, action)
    • whenGreaterEqual(value, action)
    The Waitable classes are not always spectacularly efficient since they provide notifications on all value changes. They are designed for use in contexts where either performance is not an overriding issue, or where nearly every update releases guarded waits anyway.

    Other methods
    This class implements Executor, and provides an execute method that runs the runnable within the lock.

    All classes except SynchronizedRef and WaitableRef implement Cloneable and Comparable. Implementations of the corresponding methods either use default mechanics, or use methods that closely correspond to their java.lang analogs. SynchronizedRef does not implement any of these standard interfaces because there are many cases where it would not make sense. However, you can easily make simple subclasses that add the appropriate declarations.

    [ Introduction to this package. ]

    • Field Summary

      Fields 
      Modifier and Type Field Description
      protected java.util.concurrent.locks.ReadWriteLock lock  
    • Constructor Summary

      Constructors 
      Constructor Description
      SynchronizedVariable()
      Create a SynchronizedVariable using itself as the lock *
      SynchronizedVariable​(java.util.concurrent.locks.ReadWriteLock lock)
      Create a SynchronizedVariable using the supplied lock *
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void execute​(java.lang.Runnable command)
      If current thread is not interrupted, execute the given command within this object's lock
      java.util.concurrent.locks.ReadWriteLock getLock()
      Return the lock used for all synchronization for this object
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • lock

        protected final java.util.concurrent.locks.ReadWriteLock lock
    • Constructor Detail

      • SynchronizedVariable

        public SynchronizedVariable​(java.util.concurrent.locks.ReadWriteLock lock)
        Create a SynchronizedVariable using the supplied lock *
      • SynchronizedVariable

        public SynchronizedVariable()
        Create a SynchronizedVariable using itself as the lock *
    • Method Detail

      • getLock

        public java.util.concurrent.locks.ReadWriteLock getLock()
        Return the lock used for all synchronization for this object
      • execute

        public void execute​(java.lang.Runnable command)
        If current thread is not interrupted, execute the given command within this object's lock
        Specified by:
        execute in interface java.util.concurrent.Executor