1 /*
2 File: SynchronizedVariable.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 30Jun1998 dl Create public version
12 */
13
14 package org.dbunit.util.concurrent;
15
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 /**
20 * Base class for simple, small classes
21 * maintaining single values that are always accessed
22 * and updated under synchronization. Since defining them for only
23 * some types seemed too arbitrary, they exist for all basic types,
24 * although it is hard to imagine uses for some.
25 * <p>
26 * These classes mainly exist so that you do not have to go to the
27 * trouble of writing your own miscellaneous classes and methods
28 * in situations including:
29 * <ul>
30 * <li> When you need or want to offload an instance
31 * variable to use its own synchronization lock.
32 * When these objects are used to replace instance variables, they
33 * should almost always be declared as <code>final</code>. This
34 * helps avoid the need to synchronize just to obtain the reference
35 * to the synchronized variable itself.
36 *
37 * <li> When you need methods such as set, commit, or swap.
38 * Note however that
39 * the synchronization for these variables is <em>independent</em>
40 * of any other synchronization perfromed using other locks.
41 * So, they are not
42 * normally useful when accesses and updates among
43 * variables must be coordinated.
44 * For example, it would normally be a bad idea to make
45 * a Point class out of two SynchronizedInts, even those
46 * sharing a lock.
47 *
48 * <li> When defining <code>static</code> variables. It almost
49 * always works out better to rely on synchronization internal
50 * to these objects, rather than class locks.
51 * </ul>
52 * <p>
53 * While they cannot, by nature, share much code,
54 * all of these classes work in the same way.
55 * <p>
56 * <b>Construction</b> <br>
57 * Synchronized variables are always constructed holding an
58 * initial value of the associated type. Constructors also
59 * establish the lock to use for all methods:
60 * <ul>
61 * <li> By default, each variable uses itself as the
62 * synchronization lock. This is the most common
63 * choice in the most common usage contexts in which
64 * SynchronizedVariables are used to split off
65 * synchronization locks for independent attributes
66 * of a class.
67 * <li> You can specify any other Object to use as the
68 * synchronization lock. This allows you to
69 * use various forms of `slave synchronization'. For
70 * example, a variable that is always associated with a
71 * particular object can use that object's lock.
72 * </ul>
73 * <p>
74 * <b>Update methods</b><br>
75 * Each class supports several kinds of update methods:
76 * <ul>
77 * <li> A <code>set</code> method that sets to a new value and returns
78 * previous value. For example, for a SynchronizedBoolean b,
79 * <code>boolean old = b.set(true)</code> performs a test-and-set.
80 * <p>
81 * <li> A <code>commit</code> method that sets to new value only
82 * if currently holding a given value.
83 *
84 * For example, here is a class that uses an optimistic update
85 * loop to recompute a count variable represented as a
86 * SynchronizedInt.
87 * <pre>
88 * class X {
89 * private final SynchronizedInt count = new SynchronizedInt(0);
90 *
91 * static final int MAX_RETRIES = 1000;
92 *
93 * public boolean recomputeCount() throws InterruptedException {
94 * for (int i = 0; i < MAX_RETRIES; ++i) {
95 * int current = count.get();
96 * int next = compute(current);
97 * if (count.commit(current, next))
98 * return true;
99 * else if (Thread.interrupted())
100 * throw new InterruptedException();
101 * }
102 * return false;
103 * }
104 * int compute(int l) { ... some kind of computation ... }
105 * }
106 * </pre>
107 * <p>
108 * <li>A <code>swap</code> method that atomically swaps with another
109 * object of the same class using a deadlock-avoidance strategy.
110 * <p>
111 * <li> Update-in-place methods appropriate to the type. All
112 * numerical types support:
113 * <ul>
114 * <li> add(x) (equivalent to return value += x)
115 * <li> subtract(x) (equivalent to return value -= x)
116 * <li> multiply(x) (equivalent to return value *= x)
117 * <li> divide(x) (equivalent to return value /= x)
118 * </ul>
119 * Integral types also support:
120 * <ul>
121 * <li> increment() (equivalent to return ++value)
122 * <li> decrement() (equivalent to return --value)
123 * </ul>
124 * Boolean types support:
125 * <ul>
126 * <li> or(x) (equivalent to return value |= x)
127 * <li> and(x) (equivalent to return value &= x)
128 * <li> xor(x) (equivalent to return value ^= x)
129 * <li> complement() (equivalent to return x = !x)
130 * </ul>
131 * These cover most, but not all of the possible operators in Java.
132 * You can add more compute-and-set methods in subclasses. This
133 * is often a good way to avoid the need for ad-hoc synchronized
134 * blocks surrounding expressions.
135 * </ul>
136 * <p>
137 * <b>Guarded methods</b> <br>
138 * All <code>Waitable</code> subclasses provide notifications on
139 * every value update, and support guarded methods of the form
140 * <code>when</code><em>predicate</em>, that wait until the
141 * predicate hold, then optionally run any Runnable action
142 * within the lock, and then return. All types support:
143 * <ul>
144 * <li> whenEqual(value, action)
145 * <li> whenNotEqual(value, action)
146 * </ul>
147 * (If the action argument is null, these return immediately
148 * after the predicate holds.)
149 * Numerical types also support
150 * <ul>
151 * <li> whenLess(value, action)
152 * <li> whenLessEqual(value, action)
153 * <li> whenGreater(value, action)
154 * <li> whenGreaterEqual(value, action)
155 * </ul>
156 * The Waitable classes are not always spectacularly efficient since they
157 * provide notifications on all value changes. They are
158 * designed for use in contexts where either performance is not an
159 * overriding issue, or where nearly every update releases guarded
160 * waits anyway.
161 * <p>
162 * <b>Other methods</b> <br>
163 * This class implements Executor, and provides an <code>execute</code>
164 * method that runs the runnable within the lock.
165 * <p>
166 * All classes except SynchronizedRef and WaitableRef implement
167 * <code>Cloneable</code> and <code>Comparable</code>.
168 * Implementations of the corresponding
169 * methods either use default mechanics, or use methods that closely
170 * correspond to their java.lang analogs. SynchronizedRef does not
171 * implement any of these standard interfaces because there are
172 * many cases where it would not make sense. However, you can
173 * easily make simple subclasses that add the appropriate declarations.
174 *
175 * <p>
176 *
177 *
178 *
179 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]</p>
180 *
181 * @author Doug Lea
182 * @author Last changed by: $Author$
183 * @version $Revision$ $Date$
184 * @since ? (pre 2.1)
185 */
186 public class SynchronizedVariable implements Executor {
187
188 /**
189 * Logger for this class
190 */
191 private static final Logger logger = LoggerFactory.getLogger(SynchronizedVariable.class);
192
193 protected final Object lock_;
194
195 /** Create a SynchronizedVariable using the supplied lock **/
196 public SynchronizedVariable(Object lock) { lock_ = lock; }
197
198 /** Create a SynchronizedVariable using itself as the lock **/
199 public SynchronizedVariable() { lock_ = this; }
200
201 /**
202 * Return the lock used for all synchronization for this object
203 **/
204 public Object getLock() {
205 return lock_;
206 }
207
208 /**
209 * If current thread is not interrupted, execute the given command
210 * within this object's lock
211 **/
212
213 public void execute(Runnable command) throws InterruptedException {
214 logger.debug("execute(command={}) - start", command);
215 if (Thread.interrupted()) throw new InterruptedException();
216 synchronized (lock_) {
217 command.run();
218 }
219 }
220 }