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