Showing the changes to java/pkg/java/util/concurrent/Exchanger.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,687 @@ | |||
| 1 | /* | ||
| 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 3 | * | ||
| 4 | * This code is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 only, as | ||
| 6 | * published by the Free Software Foundation. Oracle designates this | ||
| 7 | * particular file as subject to the "Classpath" exception as provided | ||
| 8 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 9 | * | ||
| 10 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 14 | * accompanied this code). | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License version | ||
| 17 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | * | ||
| 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 21 | * or visit www.oracle.com if you need additional information or have any | ||
| 22 | * questions. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * This file is available under and governed by the GNU General Public | ||
| 27 | * License version 2 only, as published by the Free Software Foundation. | ||
| 28 | * However, the following notice accompanied the original version of this | ||
| 29 | * file: | ||
| 30 | * | ||
| 31 | * Written by Doug Lea, Bill Scherer, and Michael Scott with | ||
| 32 | * assistance from members of JCP JSR-166 Expert Group and released to | ||
| 33 | * the public domain, as explained at | ||
| 34 | * http://creativecommons.org/publicdomain/zero/1.0/ | ||
| 35 | */ | ||
| 36 | |||
| 37 | package java.util.concurrent; | ||
| 38 | import java.util.concurrent.atomic.*; | ||
| 39 | import java.util.concurrent.locks.LockSupport; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * A synchronization point at which threads can pair and swap elements | ||
| 43 | * within pairs. Each thread presents some object on entry to the | ||
| 44 | * {@link #exchange exchange} method, matches with a partner thread, | ||
| 45 | * and receives its partner's object on return. An Exchanger may be | ||
| 46 | * viewed as a bidirectional form of a {@link SynchronousQueue}. | ||
| 47 | * Exchangers may be useful in applications such as genetic algorithms | ||
| 48 | * and pipeline designs. | ||
| 49 | * | ||
| 50 | * <p><b>Sample Usage:</b> | ||
| 51 | * Here are the highlights of a class that uses an {@code Exchanger} | ||
| 52 | * to swap buffers between threads so that the thread filling the | ||
| 53 | * buffer gets a freshly emptied one when it needs it, handing off the | ||
| 54 | * filled one to the thread emptying the buffer. | ||
| 55 | * <pre>{@code | ||
| 56 | * class FillAndEmpty { | ||
| 57 | * Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>(); | ||
| 58 | * DataBuffer initialEmptyBuffer = ... a made-up type | ||
| 59 | * DataBuffer initialFullBuffer = ... | ||
| 60 | * | ||
| 61 | * class FillingLoop implements Runnable { | ||
| 62 | * public void run() { | ||
| 63 | * DataBuffer currentBuffer = initialEmptyBuffer; | ||
| 64 | * try { | ||
| 65 | * while (currentBuffer != null) { | ||
| 66 | * addToBuffer(currentBuffer); | ||
| 67 | * if (currentBuffer.isFull()) | ||
| 68 | * currentBuffer = exchanger.exchange(currentBuffer); | ||
| 69 | * } | ||
| 70 | * } catch (InterruptedException ex) { ... handle ... } | ||
| 71 | * } | ||
| 72 | * } | ||
| 73 | * | ||
| 74 | * class EmptyingLoop implements Runnable { | ||
| 75 | * public void run() { | ||
| 76 | * DataBuffer currentBuffer = initialFullBuffer; | ||
| 77 | * try { | ||
| 78 | * while (currentBuffer != null) { | ||
| 79 | * takeFromBuffer(currentBuffer); | ||
| 80 | * if (currentBuffer.isEmpty()) | ||
| 81 | * currentBuffer = exchanger.exchange(currentBuffer); | ||
| 82 | * } | ||
| 83 | * } catch (InterruptedException ex) { ... handle ...} | ||
| 84 | * } | ||
| 85 | * } | ||
| 86 | * | ||
| 87 | * void start() { | ||
| 88 | * new Thread(new FillingLoop()).start(); | ||
| 89 | * new Thread(new EmptyingLoop()).start(); | ||
| 90 | * } | ||
| 91 | * } | ||
| 92 | * }</pre> | ||
| 93 | * | ||
| 94 | * <p>Memory consistency effects: For each pair of threads that | ||
| 95 | * successfully exchange objects via an {@code Exchanger}, actions | ||
| 96 | * prior to the {@code exchange()} in each thread | ||
| 97 | * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> | ||
| 98 | * those subsequent to a return from the corresponding {@code exchange()} | ||
| 99 | * in the other thread. | ||
| 100 | * | ||
| 101 | * @since 1.5 | ||
| 102 | * @author Doug Lea and Bill Scherer and Michael Scott | ||
| 103 | * @param <V> The type of objects that may be exchanged | ||
| 104 | */ | ||
| 105 | public class Exchanger<V> { | ||
| 106 | /* | ||
| 107 | * Algorithm Description: | ||
| 108 | * | ||
| 109 | * The basic idea is to maintain a "slot", which is a reference to | ||
| 110 | * a Node containing both an Item to offer and a "hole" waiting to | ||
| 111 | * get filled in. If an incoming "occupying" thread sees that the | ||
| 112 | * slot is null, it CAS'es (compareAndSets) a Node there and waits | ||
| 113 | * for another to invoke exchange. That second "fulfilling" thread | ||
| 114 | * sees that the slot is non-null, and so CASes it back to null, | ||
| 115 | * also exchanging items by CASing the hole, plus waking up the | ||
| 116 | * occupying thread if it is blocked. In each case CAS'es may | ||
| 117 | * fail because a slot at first appears non-null but is null upon | ||
| 118 | * CAS, or vice-versa. So threads may need to retry these | ||
| 119 | * actions. | ||
| 120 | * | ||
| 121 | * This simple approach works great when there are only a few | ||
| 122 | * threads using an Exchanger, but performance rapidly | ||
| 123 | * deteriorates due to CAS contention on the single slot when | ||
| 124 | * there are lots of threads using an exchanger. So instead we use | ||
| 125 | * an "arena"; basically a kind of hash table with a dynamically | ||
| 126 | * varying number of slots, any one of which can be used by | ||
| 127 | * threads performing an exchange. Incoming threads pick slots | ||
| 128 | * based on a hash of their Thread ids. If an incoming thread | ||
| 129 | * fails to CAS in its chosen slot, it picks an alternative slot | ||
| 130 | * instead. And similarly from there. If a thread successfully | ||
| 131 | * CASes into a slot but no other thread arrives, it tries | ||
| 132 | * another, heading toward the zero slot, which always exists even | ||
| 133 | * if the table shrinks. The particular mechanics controlling this | ||
| 134 | * are as follows: | ||
| 135 | * | ||
| 136 | * Waiting: Slot zero is special in that it is the only slot that | ||
| 137 | * exists when there is no contention. A thread occupying slot | ||
| 138 | * zero will block if no thread fulfills it after a short spin. | ||
| 139 | * In other cases, occupying threads eventually give up and try | ||
| 140 | * another slot. Waiting threads spin for a while (a period that | ||
| 141 | * should be a little less than a typical context-switch time) | ||
| 142 | * before either blocking (if slot zero) or giving up (if other | ||
| 143 | * slots) and restarting. There is no reason for threads to block | ||
| 144 | * unless there are unlikely to be any other threads present. | ||
| 145 | * Occupants are mainly avoiding memory contention so sit there | ||
| 146 | * quietly polling for a shorter period than it would take to | ||
| 147 | * block and then unblock them. Non-slot-zero waits that elapse | ||
| 148 | * because of lack of other threads waste around one extra | ||
| 149 | * context-switch time per try, which is still on average much | ||
| 150 | * faster than alternative approaches. | ||
| 151 | * | ||
| 152 | * Sizing: Usually, using only a few slots suffices to reduce | ||
| 153 | * contention. Especially with small numbers of threads, using | ||
| 154 | * too many slots can lead to just as poor performance as using | ||
| 155 | * too few of them, and there's not much room for error. The | ||
| 156 | * variable "max" maintains the number of slots actually in | ||
| 157 | * use. It is increased when a thread sees too many CAS | ||
| 158 | * failures. (This is analogous to resizing a regular hash table | ||
| 159 | * based on a target load factor, except here, growth steps are | ||
| 160 | * just one-by-one rather than proportional.) Growth requires | ||
| 161 | * contention failures in each of three tried slots. Requiring | ||
| 162 | * multiple failures for expansion copes with the fact that some | ||
| 163 | * failed CASes are not due to contention but instead to simple | ||
| 164 | * races between two threads or thread pre-emptions occurring | ||
| 165 | * between reading and CASing. Also, very transient peak | ||
| 166 | * contention can be much higher than the average sustainable | ||
| 167 | * levels. An attempt to decrease the max limit is usually made | ||
| 168 | * when a non-slot-zero wait elapses without being fulfilled. | ||
| 169 | * Threads experiencing elapsed waits move closer to zero, so | ||
| 170 | * eventually find existing (or future) threads even if the table | ||
| 171 | * has been shrunk due to inactivity. The chosen mechanics and | ||
| 172 | * thresholds for growing and shrinking are intrinsically | ||
| 173 | * entangled with indexing and hashing inside the exchange code, | ||
| 174 | * and can't be nicely abstracted out. | ||
| 175 | * | ||
| 176 | * Hashing: Each thread picks its initial slot to use in accord | ||
| 177 | * with a simple hashcode. The sequence is the same on each | ||
| 178 | * encounter by any given thread, but effectively random across | ||
| 179 | * threads. Using arenas encounters the classic cost vs quality | ||
| 180 | * tradeoffs of all hash tables. Here, we use a one-step FNV-1a | ||
| 181 | * hash code based on the current thread's Thread.getId(), along | ||
| 182 | * with a cheap approximation to a mod operation to select an | ||
| 183 | * index. The downside of optimizing index selection in this way | ||
| 184 | * is that the code is hardwired to use a maximum table size of | ||
| 185 | * 32. But this value more than suffices for known platforms and | ||
| 186 | * applications. | ||
| 187 | * | ||
| 188 | * Probing: On sensed contention of a selected slot, we probe | ||
| 189 | * sequentially through the table, analogously to linear probing | ||
| 190 | * after collision in a hash table. (We move circularly, in | ||
| 191 | * reverse order, to mesh best with table growth and shrinkage | ||
| 192 | * rules.) Except that to minimize the effects of false-alarms | ||
| 193 | * and cache thrashing, we try the first selected slot twice | ||
| 194 | * before moving. | ||
| 195 | * | ||
| 196 | * Padding: Even with contention management, slots are heavily | ||
| 197 | * contended, so use cache-padding to avoid poor memory | ||
| 198 | * performance. Because of this, slots are lazily constructed | ||
| 199 | * only when used, to avoid wasting this space unnecessarily. | ||
| 200 | * While isolation of locations is not much of an issue at first | ||
| 201 | * in an application, as time goes on and garbage-collectors | ||
| 202 | * perform compaction, slots are very likely to be moved adjacent | ||
| 203 | * to each other, which can cause much thrashing of cache lines on | ||
| 204 | * MPs unless padding is employed. | ||
| 205 | * | ||
| 206 | * This is an improvement of the algorithm described in the paper | ||
| 207 | * "A Scalable Elimination-based Exchange Channel" by William | ||
| 208 | * Scherer, Doug Lea, and Michael Scott in Proceedings of SCOOL05 | ||
| 209 | * workshop. Available at: http://hdl.handle.net/1802/2104 | ||
| 210 | */ | ||
| 211 | |||
| 212 | /** The number of CPUs, for sizing and spin control */ | ||
| 213 | private static final int NCPU = Runtime.getRuntime().availableProcessors(); | ||
| 214 | |||
| 215 | /** | ||
| 216 | * The capacity of the arena. Set to a value that provides more | ||
| 217 | * than enough space to handle contention. On small machines | ||
| 218 | * most slots won't be used, but it is still not wasted because | ||
| 219 | * the extra space provides some machine-level address padding | ||
| 220 | * to minimize interference with heavily CAS'ed Slot locations. | ||
| 221 | * And on very large machines, performance eventually becomes | ||
| 222 | * bounded by memory bandwidth, not numbers of threads/CPUs. | ||
| 223 | * This constant cannot be changed without also modifying | ||
| 224 | * indexing and hashing algorithms. | ||
| 225 | */ | ||
| 226 | private static final int CAPACITY = 32; | ||
| 227 | |||
| 228 | /** | ||
| 229 | * The value of "max" that will hold all threads without | ||
| 230 | * contention. When this value is less than CAPACITY, some | ||
| 231 | * otherwise wasted expansion can be avoided. | ||
| 232 | */ | ||
| 233 | private static final int FULL = | ||
| 234 | Math.max(0, Math.min(CAPACITY, NCPU / 2) - 1); | ||
| 235 | |||
| 236 | /** | ||
| 237 | * The number of times to spin (doing nothing except polling a | ||
| 238 | * memory location) before blocking or giving up while waiting to | ||
| 239 | * be fulfilled. Should be zero on uniprocessors. On | ||
| 240 | * multiprocessors, this value should be large enough so that two | ||
| 241 | * threads exchanging items as fast as possible block only when | ||
| 242 | * one of them is stalled (due to GC or preemption), but not much | ||
| 243 | * longer, to avoid wasting CPU resources. Seen differently, this | ||
| 244 | * value is a little over half the number of cycles of an average | ||
| 245 | * context switch time on most systems. The value here is | ||
| 246 | * approximately the average of those across a range of tested | ||
| 247 | * systems. | ||
| 248 | */ | ||
| 249 | private static final int SPINS = (NCPU == 1) ? 0 : 2000; | ||
| 250 | |||
| 251 | /** | ||
| 252 | * The number of times to spin before blocking in timed waits. | ||
| 253 | * Timed waits spin more slowly because checking the time takes | ||
| 254 | * time. The best value relies mainly on the relative rate of | ||
| 255 | * System.nanoTime vs memory accesses. The value is empirically | ||
| 256 | * derived to work well across a variety of systems. | ||
| 257 | */ | ||
| 258 | private static final int TIMED_SPINS = SPINS / 20; | ||
| 259 | |||
| 260 | /** | ||
| 261 | * Sentinel item representing cancellation of a wait due to | ||
| 262 | * interruption, timeout, or elapsed spin-waits. This value is | ||
| 263 | * placed in holes on cancellation, and used as a return value | ||
| 264 | * from waiting methods to indicate failure to set or get hole. | ||
| 265 | */ | ||
| 266 | private static final Object CANCEL = new Object(); | ||
| 267 | |||
| 268 | /** | ||
| 269 | * Value representing null arguments/returns from public | ||
| 270 | * methods. This disambiguates from internal requirement that | ||
| 271 | * holes start out as null to mean they are not yet set. | ||
| 272 | */ | ||
| 273 | private static final Object NULL_ITEM = new Object(); | ||
| 274 | |||
| 275 | /** | ||
| 276 | * Nodes hold partially exchanged data. This class | ||
| 277 | * opportunistically subclasses AtomicReference to represent the | ||
| 278 | * hole. So get() returns hole, and compareAndSet CAS'es value | ||
| 279 | * into hole. This class cannot be parameterized as "V" because | ||
| 280 | * of the use of non-V CANCEL sentinels. | ||
| 281 | */ | ||
| 282 | private static final class Node extends AtomicReference<Object> { | ||
| 283 | /** The element offered by the Thread creating this node. */ | ||
| 284 | public final Object item; | ||
| 285 | |||
| 286 | /** The Thread waiting to be signalled; null until waiting. */ | ||
| 287 | public volatile Thread waiter; | ||
| 288 | |||
| 289 | /** | ||
| 290 | * Creates node with given item and empty hole. | ||
| 291 | * @param item the item | ||
| 292 | */ | ||
| 293 | public Node(Object item) { | ||
| 294 | this.item = item; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | /** | ||
| 299 | * A Slot is an AtomicReference with heuristic padding to lessen | ||
| 300 | * cache effects of this heavily CAS'ed location. While the | ||
| 301 | * padding adds noticeable space, all slots are created only on | ||
| 302 | * demand, and there will be more than one of them only when it | ||
| 303 | * would improve throughput more than enough to outweigh using | ||
| 304 | * extra space. | ||
| 305 | */ | ||
| 306 | private static final class Slot extends AtomicReference<Object> { | ||
| 307 | // Improve likelihood of isolation on <= 64 byte cache lines | ||
| 308 | long q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, qa, qb, qc, qd, qe; | ||
| 309 | } | ||
| 310 | |||
| 311 | /** | ||
| 312 | * Slot array. Elements are lazily initialized when needed. | ||
| 313 | * Declared volatile to enable double-checked lazy construction. | ||
| 314 | */ | ||
| 315 | private volatile Slot[] arena = new Slot[CAPACITY]; | ||
| 316 | |||
| 317 | /** | ||
| 318 | * The maximum slot index being used. The value sometimes | ||
| 319 | * increases when a thread experiences too many CAS contentions, | ||
| 320 | * and sometimes decreases when a spin-wait elapses. Changes | ||
| 321 | * are performed only via compareAndSet, to avoid stale values | ||
| 322 | * when a thread happens to stall right before setting. | ||
| 323 | */ | ||
| 324 | private final AtomicInteger max = new AtomicInteger(); | ||
| 325 | |||
| 326 | /** | ||
| 327 | * Main exchange function, handling the different policy variants. | ||
| 328 | * Uses Object, not "V" as argument and return value to simplify | ||
| 329 | * handling of sentinel values. Callers from public methods decode | ||
| 330 | * and cast accordingly. | ||
| 331 | * | ||
| 332 | * @param item the (non-null) item to exchange | ||
| 333 | * @param timed true if the wait is timed | ||
| 334 | * @param nanos if timed, the maximum wait time | ||
| 335 | * @return the other thread's item, or CANCEL if interrupted or timed out | ||
| 336 | */ | ||
| 337 | private Object doExchange(Object item, boolean timed, long nanos) { | ||
| 338 | Node me = new Node(item); // Create in case occupying | ||
| 339 | int index = hashIndex(); // Index of current slot | ||
| 340 | int fails = 0; // Number of CAS failures | ||
| 341 | |||
| 342 | for (;;) { | ||
| 343 | Object y; // Contents of current slot | ||
| 344 | Slot slot = arena[index]; | ||
| 345 | if (slot == null) // Lazily initialize slots | ||
| 346 | createSlot(index); // Continue loop to reread | ||
| 347 | else if ((y = slot.get()) != null && // Try to fulfill | ||
| 348 | slot.compareAndSet(y, null)) { | ||
| 349 | Node you = (Node)y; // Transfer item | ||
| 350 | if (you.compareAndSet(null, item)) { | ||
| 351 | LockSupport.unpark(you.waiter); | ||
| 352 | return you.item; | ||
| 353 | } // Else cancelled; continue | ||
| 354 | } | ||
| 355 | else if (y == null && // Try to occupy | ||
| 356 | slot.compareAndSet(null, me)) { | ||
| 357 | if (index == 0) // Blocking wait for slot 0 | ||
| 358 | return timed ? | ||
| 359 | awaitNanos(me, slot, nanos) : | ||
| 360 | await(me, slot); | ||
| 361 | Object v = spinWait(me, slot); // Spin wait for non-0 | ||
| 362 | if (v != CANCEL) | ||
| 363 | return v; | ||
| 364 | me = new Node(item); // Throw away cancelled node | ||
| 365 | int m = max.get(); | ||
| 366 | if (m > (index >>>= 1)) // Decrease index | ||
| 367 | max.compareAndSet(m, m - 1); // Maybe shrink table | ||
| 368 | } | ||
| 369 | else if (++fails > 1) { // Allow 2 fails on 1st slot | ||
| 370 | int m = max.get(); | ||
| 371 | if (fails > 3 && m < FULL && max.compareAndSet(m, m + 1)) | ||
| 372 | index = m + 1; // Grow on 3rd failed slot | ||
| 373 | else if (--index < 0) | ||
| 374 | index = m; // Circularly traverse | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | /** | ||
| 380 | * Returns a hash index for the current thread. Uses a one-step | ||
| 381 | * FNV-1a hash code (http://www.isthe.com/chongo/tech/comp/fnv/) | ||
| 382 | * based on the current thread's Thread.getId(). These hash codes | ||
| 383 | * have more uniform distribution properties with respect to small | ||
| 384 | * moduli (here 1-31) than do other simple hashing functions. | ||
| 385 | * | ||
| 386 | * <p>To return an index between 0 and max, we use a cheap | ||
| 387 | * approximation to a mod operation, that also corrects for bias | ||
| 388 | * due to non-power-of-2 remaindering (see {@link | ||
| 389 | * java.util.Random#nextInt}). Bits of the hashcode are masked | ||
| 390 | * with "nbits", the ceiling power of two of table size (looked up | ||
| 391 | * in a table packed into three ints). If too large, this is | ||
| 392 | * retried after rotating the hash by nbits bits, while forcing new | ||
| 393 | * top bit to 0, which guarantees eventual termination (although | ||
| 394 | * with a non-random-bias). This requires an average of less than | ||
| 395 | * 2 tries for all table sizes, and has a maximum 2% difference | ||
| 396 | * from perfectly uniform slot probabilities when applied to all | ||
| 397 | * possible hash codes for sizes less than 32. | ||
| 398 | * | ||
| 399 | * @return a per-thread-random index, 0 <= index < max | ||
| 400 | */ | ||
| 401 | private final int hashIndex() { | ||
| 402 | long id = Thread.currentThread().getId(); | ||
| 403 | int hash = (((int)(id ^ (id >>> 32))) ^ 0x811c9dc5) * 0x01000193; | ||
| 404 | |||
| 405 | int m = max.get(); | ||
| 406 | int nbits = (((0xfffffc00 >> m) & 4) | // Compute ceil(log2(m+1)) | ||
| 407 | ((0x000001f8 >>> m) & 2) | // The constants hold | ||
| 408 | ((0xffff00f2 >>> m) & 1)); // a lookup table | ||
| 409 | int index; | ||
| 410 | while ((index = hash & ((1 << nbits) - 1)) > m) // May retry on | ||
| 411 | hash = (hash >>> nbits) | (hash << (33 - nbits)); // non-power-2 m | ||
| 412 | return index; | ||
| 413 | } | ||
| 414 | |||
| 415 | /** | ||
| 416 | * Creates a new slot at given index. Called only when the slot | ||
| 417 | * appears to be null. Relies on double-check using builtin | ||
| 418 | * locks, since they rarely contend. This in turn relies on the | ||
| 419 | * arena array being declared volatile. | ||
| 420 | * | ||
| 421 | * @param index the index to add slot at | ||
| 422 | */ | ||
| 423 | private void createSlot(int index) { | ||
| 424 | // Create slot outside of lock to narrow sync region | ||
| 425 | Slot newSlot = new Slot(); | ||
| 426 | Slot[] a = arena; | ||
| 427 | synchronized (a) { | ||
| 428 | if (a[index] == null) | ||
| 429 | a[index] = newSlot; | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | /** | ||
| 434 | * Tries to cancel a wait for the given node waiting in the given | ||
| 435 | * slot, if so, helping clear the node from its slot to avoid | ||
| 436 | * garbage retention. | ||
| 437 | * | ||
| 438 | * @param node the waiting node | ||
| 439 | * @param the slot it is waiting in | ||
| 440 | * @return true if successfully cancelled | ||
| 441 | */ | ||
| 442 | private static boolean tryCancel(Node node, Slot slot) { | ||
| 443 | if (!node.compareAndSet(null, CANCEL)) | ||
| 444 | return false; | ||
| 445 | if (slot.get() == node) // pre-check to minimize contention | ||
| 446 | slot.compareAndSet(node, null); | ||
| 447 | return true; | ||
| 448 | } | ||
| 449 | |||
| 450 | // Three forms of waiting. Each just different enough not to merge | ||
| 451 | // code with others. | ||
| 452 | |||
| 453 | /** | ||
| 454 | * Spin-waits for hole for a non-0 slot. Fails if spin elapses | ||
| 455 | * before hole filled. Does not check interrupt, relying on check | ||
| 456 | * in public exchange method to abort if interrupted on entry. | ||
| 457 | * | ||
| 458 | * @param node the waiting node | ||
| 459 | * @return on success, the hole; on failure, CANCEL | ||
| 460 | */ | ||
| 461 | private static Object spinWait(Node node, Slot slot) { | ||
| 462 | int spins = SPINS; | ||
| 463 | for (;;) { | ||
| 464 | Object v = node.get(); | ||
| 465 | if (v != null) | ||
| 466 | return v; | ||
| 467 | else if (spins > 0) | ||
| 468 | --spins; | ||
| 469 | else | ||
| 470 | tryCancel(node, slot); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | /** | ||
| 475 | * Waits for (by spinning and/or blocking) and gets the hole | ||
| 476 | * filled in by another thread. Fails if interrupted before | ||
| 477 | * hole filled. | ||
| 478 | * | ||
| 479 | * When a node/thread is about to block, it sets its waiter field | ||
| 480 | * and then rechecks state at least one more time before actually | ||
| 481 | * parking, thus covering race vs fulfiller noticing that waiter | ||
| 482 | * is non-null so should be woken. | ||
| 483 | * | ||
| 484 | * Thread interruption status is checked only surrounding calls to | ||
| 485 | * park. The caller is assumed to have checked interrupt status | ||
| 486 | * on entry. | ||
| 487 | * | ||
| 488 | * @param node the waiting node | ||
| 489 | * @return on success, the hole; on failure, CANCEL | ||
| 490 | */ | ||
| 491 | private static Object await(Node node, Slot slot) { | ||
| 492 | Thread w = Thread.currentThread(); | ||
| 493 | int spins = SPINS; | ||
| 494 | for (;;) { | ||
| 495 | Object v = node.get(); | ||
| 496 | if (v != null) | ||
| 497 | return v; | ||
| 498 | else if (spins > 0) // Spin-wait phase | ||
| 499 | --spins; | ||
| 500 | else if (node.waiter == null) // Set up to block next | ||
| 501 | node.waiter = w; | ||
| 502 | else if (w.isInterrupted()) // Abort on interrupt | ||
| 503 | tryCancel(node, slot); | ||
| 504 | else // Block | ||
| 505 | LockSupport.park(node); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | /** | ||
| 510 | * Waits for (at index 0) and gets the hole filled in by another | ||
| 511 | * thread. Fails if timed out or interrupted before hole filled. | ||
| 512 | * Same basic logic as untimed version, but a bit messier. | ||
| 513 | * | ||
| 514 | * @param node the waiting node | ||
| 515 | * @param nanos the wait time | ||
| 516 | * @return on success, the hole; on failure, CANCEL | ||
| 517 | */ | ||
| 518 | private Object awaitNanos(Node node, Slot slot, long nanos) { | ||
| 519 | int spins = TIMED_SPINS; | ||
| 520 | long lastTime = 0; | ||
| 521 | Thread w = null; | ||
| 522 | for (;;) { | ||
| 523 | Object v = node.get(); | ||
| 524 | if (v != null) | ||
| 525 | return v; | ||
| 526 | long now = System.nanoTime(); | ||
| 527 | if (w == null) | ||
| 528 | w = Thread.currentThread(); | ||
| 529 | else | ||
| 530 | nanos -= now - lastTime; | ||
| 531 | lastTime = now; | ||
| 532 | if (nanos > 0) { | ||
| 533 | if (spins > 0) | ||
| 534 | --spins; | ||
| 535 | else if (node.waiter == null) | ||
| 536 | node.waiter = w; | ||
| 537 | else if (w.isInterrupted()) | ||
| 538 | tryCancel(node, slot); | ||
| 539 | else | ||
| 540 | LockSupport.parkNanos(node, nanos); | ||
| 541 | } | ||
| 542 | else if (tryCancel(node, slot) && !w.isInterrupted()) | ||
| 543 | return scanOnTimeout(node); | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | /** | ||
| 548 | * Sweeps through arena checking for any waiting threads. Called | ||
| 549 | * only upon return from timeout while waiting in slot 0. When a | ||
| 550 | * thread gives up on a timed wait, it is possible that a | ||
| 551 | * previously-entered thread is still waiting in some other | ||
| 552 | * slot. So we scan to check for any. This is almost always | ||
| 553 | * overkill, but decreases the likelihood of timeouts when there | ||
| 554 | * are other threads present to far less than that in lock-based | ||
| 555 | * exchangers in which earlier-arriving threads may still be | ||
| 556 | * waiting on entry locks. | ||
| 557 | * | ||
| 558 | * @param node the waiting node | ||
| 559 | * @return another thread's item, or CANCEL | ||
| 560 | */ | ||
| 561 | private Object scanOnTimeout(Node node) { | ||
| 562 | Object y; | ||
| 563 | for (int j = arena.length - 1; j >= 0; --j) { | ||
| 564 | Slot slot = arena[j]; | ||
| 565 | if (slot != null) { | ||
| 566 | while ((y = slot.get()) != null) { | ||
| 567 | if (slot.compareAndSet(y, null)) { | ||
| 568 | Node you = (Node)y; | ||
| 569 | if (you.compareAndSet(null, node.item)) { | ||
| 570 | LockSupport.unpark(you.waiter); | ||
| 571 | return you.item; | ||
| 572 | } | ||
| 573 | } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | return CANCEL; | ||
| 578 | } | ||
| 579 | |||
| 580 | /** | ||
| 581 | * Creates a new Exchanger. | ||
| 582 | */ | ||
| 583 | public Exchanger() { | ||
| 584 | } | ||
| 585 | |||
| 586 | /** | ||
| 587 | * Waits for another thread to arrive at this exchange point (unless | ||
| 588 | * the current thread is {@linkplain Thread#interrupt interrupted}), | ||
| 589 | * and then transfers the given object to it, receiving its object | ||
| 590 | * in return. | ||
| 591 | * | ||
| 592 | * <p>If another thread is already waiting at the exchange point then | ||
| 593 | * it is resumed for thread scheduling purposes and receives the object | ||
| 594 | * passed in by the current thread. The current thread returns immediately, | ||
| 595 | * receiving the object passed to the exchange by that other thread. | ||
| 596 | * | ||
| 597 | * <p>If no other thread is already waiting at the exchange then the | ||
| 598 | * current thread is disabled for thread scheduling purposes and lies | ||
| 599 | * dormant until one of two things happens: | ||
| 600 | * <ul> | ||
| 601 | * <li>Some other thread enters the exchange; or | ||
| 602 | * <li>Some other thread {@linkplain Thread#interrupt interrupts} | ||
| 603 | * the current thread. | ||
| 604 | * </ul> | ||
| 605 | * <p>If the current thread: | ||
| 606 | * <ul> | ||
| 607 | * <li>has its interrupted status set on entry to this method; or | ||
| 608 | * <li>is {@linkplain Thread#interrupt interrupted} while waiting | ||
| 609 | * for the exchange, | ||
| 610 | * </ul> | ||
| 611 | * then {@link InterruptedException} is thrown and the current thread's | ||
| 612 | * interrupted status is cleared. | ||
| 613 | * | ||
| 614 | * @param x the object to exchange | ||
| 615 | * @return the object provided by the other thread | ||
| 616 | * @throws InterruptedException if the current thread was | ||
| 617 | * interrupted while waiting | ||
| 618 | */ | ||
| 619 | public V exchange(V x) throws InterruptedException { | ||
| 620 | if (!Thread.interrupted()) { | ||
| 621 | Object v = doExchange((x == null) ? NULL_ITEM : x, false, 0); | ||
| 622 | if (v == NULL_ITEM) | ||
| 623 | return null; | ||
| 624 | if (v != CANCEL) | ||
| 625 | return (V)v; | ||
| 626 | Thread.interrupted(); // Clear interrupt status on IE throw | ||
| 627 | } | ||
| 628 | throw new InterruptedException(); | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * Waits for another thread to arrive at this exchange point (unless | ||
| 633 | * the current thread is {@linkplain Thread#interrupt interrupted} or | ||
| 634 | * the specified waiting time elapses), and then transfers the given | ||
| 635 | * object to it, receiving its object in return. | ||
| 636 | * | ||
| 637 | * <p>If another thread is already waiting at the exchange point then | ||
| 638 | * it is resumed for thread scheduling purposes and receives the object | ||
| 639 | * passed in by the current thread. The current thread returns immediately, | ||
| 640 | * receiving the object passed to the exchange by that other thread. | ||
| 641 | * | ||
| 642 | * <p>If no other thread is already waiting at the exchange then the | ||
| 643 | * current thread is disabled for thread scheduling purposes and lies | ||
| 644 | * dormant until one of three things happens: | ||
| 645 | * <ul> | ||
| 646 | * <li>Some other thread enters the exchange; or | ||
| 647 | * <li>Some other thread {@linkplain Thread#interrupt interrupts} | ||
| 648 | * the current thread; or | ||
| 649 | * <li>The specified waiting time elapses. | ||
| 650 | * </ul> | ||
| 651 | * <p>If the current thread: | ||
| 652 | * <ul> | ||
| 653 | * <li>has its interrupted status set on entry to this method; or | ||
| 654 | * <li>is {@linkplain Thread#interrupt interrupted} while waiting | ||
| 655 | * for the exchange, | ||
| 656 | * </ul> | ||
| 657 | * then {@link InterruptedException} is thrown and the current thread's | ||
| 658 | * interrupted status is cleared. | ||
| 659 | * | ||
| 660 | * <p>If the specified waiting time elapses then {@link | ||
| 661 | * TimeoutException} is thrown. If the time is less than or equal | ||
| 662 | * to zero, the method will not wait at all. | ||
| 663 | * | ||
| 664 | * @param x the object to exchange | ||
| 665 | * @param timeout the maximum time to wait | ||
| 666 | * @param unit the time unit of the <tt>timeout</tt> argument | ||
| 667 | * @return the object provided by the other thread | ||
| 668 | * @throws InterruptedException if the current thread was | ||
| 669 | * interrupted while waiting | ||
| 670 | * @throws TimeoutException if the specified waiting time elapses | ||
| 671 | * before another thread enters the exchange | ||
| 672 | */ | ||
| 673 | public V exchange(V x, long timeout, TimeUnit unit) | ||
| 674 | throws InterruptedException, TimeoutException { | ||
| 675 | if (!Thread.interrupted()) { | ||
| 676 | Object v = doExchange((x == null) ? NULL_ITEM : x, | ||
| 677 | true, unit.toNanos(timeout)); | ||
| 678 | if (v == NULL_ITEM) | ||
| 679 | return null; | ||
| 680 | if (v != CANCEL) | ||
| 681 | return (V)v; | ||
| 682 | if (!Thread.interrupted()) | ||
| 683 | throw new TimeoutException(); | ||
| 684 | } | ||
| 685 | throw new InterruptedException(); | ||
| 686 | } | ||
| 687 | } | ||