1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
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.concurrent;
18
19 /***
20 * @version $Id: Sync.html 13146 2011-08-01 17:12:39Z oletizi $
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 * Acquire lock of LockType.READ or WRITE
303 * @param type the lock type to acquire
304 */
305 void lock(LockType type);
306
307 /***
308 * Tries to acquire a LockType.READ or WRITE for a certain period
309 * @param type the lock type to acquire
310 * @param msec timeout
311 * @return true if the lock got acquired, false otherwise
312 * @throws InterruptedException Should the thread be interrupted
313 */
314 boolean tryLock(LockType type, long msec) throws InterruptedException;
315
316 /***
317 * Releases the lock held by the current Thread.
318 * In case of a LockType.WRITE, should the lock not be held by the current Thread, nothing happens
319 * @param type the lock type to acquire
320 */
321 void unlock(LockType type);
322
323 /***
324 * Returns true is this is lock is held at given level by the current thread.
325 *
326 * @param type the lock type to test
327 * @return true if the lock is held
328 */
329 boolean isHeldByCurrentThread(LockType type);
330 }
331