1 /**
2 * Copyright 2003-2007 Greg Luck
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.constructs.concurrent;
18
19 /**
20 * @version $Id: Sync.java 512 2007-07-10 09:18:45Z gregluck $
21 * @author Doug Lea
22 * Main interface for locks, gates, and conditions.
23 * <p/>
24 * Sync objects isolate waiting and notification for particular
25 * logical states, resource availability, events, and the like that are
26 * shared across multiple threads. Use of Syncs sometimes
27 * (but by no means always) adds flexibility and efficiency
28 * compared to the use of plain java monitor methods
29 * and locking, and are sometimes (but by no means always)
30 * simpler to program with.
31 * <p/>
32 * <p/>
33 * Most Syncs are intended to be used primarily (although
34 * not exclusively) in before/after constructions such as:
35 * <pre>
36 * class X {
37 * Sync gate;
38 * // ...
39 * <p/>
40 * public void m() {
41 * try {
42 * gate.acquire(); // block until condition holds
43 * try {
44 * // ... method body
45 * }
46 * finally {
47 * gate.release()
48 * }
49 * }
50 * catch (InterruptedException ex) {
51 * // ... evasive action
52 * }
53 * }
54 * <p/>
55 * public void m2(Sync cond) { // use supplied condition
56 * try {
57 * if (cond.attempt(10)) { // try the condition for 10 ms
58 * try {
59 * // ... method body
60 * }
61 * finally {
62 * cond.release()
63 * }
64 * }
65 * }
66 * catch (InterruptedException ex) {
67 * // ... evasive action
68 * }
69 * }
70 * }
71 * </pre>
72 * Syncs may be used in somewhat tedious but more flexible replacements
73 * for built-in Java synchronized blocks. For example:
74 * <pre>
75 * class HandSynched {
76 * private double state_ = 0.0;
77 * private final Sync lock; // use lock type supplied in constructor
78 * public HandSynched(Sync l) { lock = l; }
79 * <p/>
80 * public void changeState(double d) {
81 * try {
82 * lock.acquire();
83 * try { state_ = updateFunction(d); }
84 * finally { lock.release(); }
85 * }
86 * catch(InterruptedException ex) { }
87 * }
88 * <p/>
89 * public double getState() {
90 * double d = 0.0;
91 * try {
92 * lock.acquire();
93 * try { d = accessFunction(state_); }
94 * finally { lock.release(); }
95 * }
96 * catch(InterruptedException ex){}
97 * return d;
98 * }
99 * private double updateFunction(double d) { ... }
100 * private double accessFunction(double d) { ... }
101 * }
102 * </pre>
103 * If you have a lot of such methods, and they take a common
104 * form, you can standardize this using wrappers. Some of these
105 * wrappers are standardized in LockedExecutor, but you can make others.
106 * For example:
107 * <pre>
108 * class HandSynchedV2 {
109 * private double state_ = 0.0;
110 * private final Sync lock; // use lock type supplied in constructor
111 * public HandSynchedV2(Sync l) { lock = l; }
112 * <p/>
113 * protected void runSafely(Runnable r) {
114 * try {
115 * lock.acquire();
116 * try { r.run(); }
117 * finally { lock.release(); }
118 * }
119 * catch (InterruptedException ex) { // propagate without throwing
120 * Thread.currentThread().interrupt();
121 * }
122 * }
123 * <p/>
124 * public void changeState(double d) {
125 * runSafely(new Runnable() {
126 * public void run() { state_ = updateFunction(d); }
127 * });
128 * }
129 * // ...
130 * }
131 * </pre>
132 * <p/>
133 * One reason to bother with such constructions is to use deadlock-
134 * avoiding back-offs when dealing with locks involving multiple objects.
135 * For example, here is a Cell class that uses attempt to back-off
136 * and retry if two Cells are trying to swap values with each other
137 * at the same time.
138 * <pre>
139 * class Cell {
140 * long value;
141 * Sync lock = ... // some sync implementation class
142 * void swapValue(Cell other) {
143 * for (;;) {
144 * try {
145 * lock.acquire();
146 * try {
147 * if (other.lock.attempt(100)) {
148 * try {
149 * long t = value;
150 * value = other.value;
151 * other.value = t;
152 * return;
153 * }
154 * finally { other.lock.release(); }
155 * }
156 * }
157 * finally { lock.release(); }
158 * }
159 * catch (InterruptedException ex) { return; }
160 * }
161 * }
162 * }
163 * </pre>
164 * <p/>
165 * Here is an even fancier version, that uses lock re-ordering
166 * upon conflict:
167 * <pre>
168 * class Cell {
169 * long value;
170 * Sync lock = ...;
171 * private static boolean trySwap(Cell a, Cell b) {
172 * a.lock.acquire();
173 * try {
174 * if (!b.lock.attempt(0))
175 * return false;
176 * try {
177 * long t = a.value;
178 * a.value = b.value;
179 * b.value = t;
180 * return true;
181 * }
182 * finally { other.lock.release(); }
183 * }
184 * finally { lock.release(); }
185 * return false;
186 * }
187 * <p/>
188 * void swapValue(Cell other) {
189 * try {
190 * while (!trySwap(this, other) &&
191 * !tryswap(other, this))
192 * Thread.sleep(1);
193 * }
194 * catch (InterruptedException ex) { return; }
195 * }
196 * }
197 * </pre>
198 * <p/>
199 * Interruptions are in general handled as early as possible.
200 * Normally, InterruptionExceptions are thrown
201 * in acquire and attempt(msec) if interruption
202 * is detected upon entry to the method, as well as in any
203 * later context surrounding waits.
204 * However, interruption status is ignored in release();
205 * <p/>
206 * Timed versions of attempt report failure via return value.
207 * If so desired, you can transform such constructions to use exception
208 * throws via
209 * <pre>
210 * if (!c.attempt(timeval)) throw new TimeoutException(timeval);
211 * </pre>
212 * <p/>
213 * The TimoutSync wrapper class can be used to automate such usages.
214 * <p/>
215 * All time values are expressed in milliseconds as longs, which have a maximum
216 * value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
217 * known whether JVMs actually deal correctly with such extreme values.
218 * For convenience, some useful time values are defined as static constants.
219 * <p/>
220 * All implementations of the three Sync methods guarantee to
221 * somehow employ Java <code>synchronized</code> methods or blocks,
222 * and so entail the memory operations described in JLS
223 * chapter 17 which ensure that variables are loaded and flushed
224 * within before/after constructions.
225 * <p/>
226 * Syncs may also be used in spinlock constructions. Although
227 * it is normally best to just use acquire(), various forms
228 * of busy waits can be implemented. For a simple example
229 * (but one that would probably never be preferable to using acquire()):
230 * <pre>
231 * class X {
232 * Sync lock = ...
233 * void spinUntilAcquired() throws InterruptedException {
234 * // Two phase.
235 * // First spin without pausing.
236 * int purespins = 10;
237 * for (int i = 0; i < purespins; ++i) {
238 * if (lock.attempt(0))
239 * return true;
240 * }
241 * // Second phase - use timed waits
242 * long waitTime = 1; // 1 millisecond
243 * for (;;) {
244 * if (lock.attempt(waitTime))
245 * return true;
246 * else
247 * waitTime = waitTime * 3 / 2 + 1; // increase 50%
248 * }
249 * }
250 * }
251 * </pre>
252 * <p/>
253 * In addition pure synchronization control, Syncs
254 * may be useful in any context requiring before/after methods.
255 * For example, you can use an ObservableSync
256 * (perhaps as part of a LayeredSync) in order to obtain callbacks
257 * before and after each method invocation for a given class.
258 * <p/>
259 * <p/>
260 * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
261 */
262 public interface Sync {
263 /**
264 * One second, in milliseconds; convenient as a time-out value *
265 */
266 long ONE_SECOND = 1000;
267
268 /**
269 * One minute, in milliseconds; convenient as a time-out value *
270 */
271 long ONE_MINUTE = 60 * ONE_SECOND;
272
273 /**
274 * One hour, in milliseconds; convenient as a time-out value *
275 */
276 long ONE_HOUR = 60 * ONE_MINUTE;
277
278 /**
279 * One day, in milliseconds; convenient as a time-out value *
280 */
281 long ONE_DAY = 24 * ONE_HOUR;
282
283 /**
284 * One week, in milliseconds; convenient as a time-out value *
285 */
286 long ONE_WEEK = 7 * ONE_DAY;
287
288 /**
289 * One year in milliseconds; convenient as a time-out value
290 * Not that it matters, but there is some variation across
291 * standard sources about value at msec precision.
292 * The value used is the same as in java.util.GregorianCalendar
293 */
294 long ONE_YEAR = (long) (365.2425 * ONE_DAY);
295
296 /**
297 * One century in milliseconds; convenient as a time-out value
298 */
299 long ONE_CENTURY = 100 * ONE_YEAR;
300
301 /**
302 * Wait (possibly forever) until successful passage.
303 * Fail only upon interuption. Interruptions always result in
304 * `clean' failures. On failure, you can be sure that it has not
305 * been acquired, and that no
306 * corresponding release should be performed. Conversely,
307 * a normal return guarantees that the acquire was successful.
308 */
309 void acquire() throws InterruptedException;
310
311 /**
312 * Wait at most msecs to pass; report whether passed.
313 * <p/>
314 * The method has best-effort semantics:
315 * The msecs bound cannot
316 * be guaranteed to be a precise upper bound on wait time in Java.
317 * Implementations generally can only attempt to return as soon as possible
318 * after the specified bound. Also, timers in Java do not stop during garbage
319 * collection, so timeouts can occur just because a GC intervened.
320 * So, msecs arguments should be used in
321 * a coarse-grained manner. Further,
322 * implementations cannot always guarantee that this method
323 * will return at all without blocking indefinitely when used in
324 * unintended ways. For example, deadlocks may be encountered
325 * when called in an unintended context.
326 * <p/>
327 *
328 * @param msecs the number of milleseconds to wait.
329 * An argument less than or equal to zero means not to wait at all.
330 * However, this may still require
331 * access to a synchronization lock, which can impose unbounded
332 * delay if there is a lot of contention among threads.
333 * @return true if acquired
334 */
335 boolean attempt(long msecs) throws InterruptedException;
336
337 /**
338 * Potentially enable others to pass.
339 * <p/>
340 * Because release does not raise exceptions,
341 * it can be used in `finally' clauses without requiring extra
342 * embedded try/catch blocks. But keep in mind that
343 * as with any java method, implementations may
344 * still throw unchecked exceptions such as Error or NullPointerException
345 * when faced with uncontinuable errors. However, these should normally
346 * only be caught by higher-level error handlers.
347 */
348 void release();
349 }
350