/* * @(#)LockSupport.java 1.6 04/01/24 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.locks; import java.util.concurrent.*; import sun.misc.Unsafe; /** * Basic thread blocking primitives for creating locks and other * synchronization classes. * *
This class associates with each thread that uses it, a permit * (in the sense of the {@link java.util.concurrent.Semaphore * Semaphore} class). A call to park will return immediately * if the permit is available, consuming it in the process; otherwise * it may block. A call to unpark makes the permit * available, if it was not already available. (Unlike with Semaphores * though, permits do not accumulate. There is at most one.) * *
Methods park and unpark provide efficient * means of blocking and unblocking threads that do not encounter the * problems that cause the deprecated methods Thread.suspend * and Thread.resume to be unusable for such purposes: Races * between one thread invoking park and another thread trying * to unpark it will preserve liveness, due to the * permit. Additionally, park will return if the caller's * thread was interrupted, and timeout versions are supported. The * park method may also return at any other time, for "no * reason", so in general must be invoked within a loop that rechecks * conditions upon return. In this sense park serves as an * optimization of a "busy wait" that does not waste as much time * spinning, but must be paired with an unpark to be * effective. * *
These methods are designed to be used as tools for creating * higher-level synchronization utilities, and are not in themselves * useful for most concurrency control applications. * *
Sample Usage. Here is a sketch of a First-in-first-out * non-reentrant lock class. *
* class FIFOMutex {
* private AtomicBoolean locked = new AtomicBoolean(false);
* private Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();
*
* public void lock() {
* boolean wasInterrupted = false;
* Thread current = Thread.currentThread();
* waiters.add(current);
*
* // Block while not first in queue or cannot acquire lock
* while (waiters.peek() != current ||
* !locked.compareAndSet(false, true)) {
* LockSupport.park();
* if (Thread.interrupted()) // ignore interrupts while waiting
* wasInterrupted = true;
* }
*
* waiters.remove();
* if (wasInterrupted) // reassert interrupt status on exit
* current.interrupt();
* }
*
* public void unlock() {
* locked.set(false);
* LockSupport.unpark(waiters.peek());
* }
* }
*
*/
public class LockSupport {
private LockSupport() {} // Cannot be instantiated.
// Hotspot implementation via intrinsics API
private static final Unsafe unsafe = Unsafe.getUnsafe();
/**
* Make available the permit for the given thread, if it
* was not already available. If the thread was blocked on
* park then it will unblock. Otherwise, its next call
* to park is guaranteed not to block. This operation
* is not guaranteed to have any effect at all if the given
* thread has not been started.
* @param thread the thread to unpark, or null, in which case
* this operation has no effect.
*/
public static void unpark(Thread thread) {
if (thread != null)
unsafe.unpark(thread);
}
/**
* Disables the current thread for thread scheduling purposes unless the
* permit is available.
* If the permit is available then it is consumed and the call returns * immediately; otherwise * the current thread becomes disabled for thread scheduling * purposes and lies dormant until one of three things happens: *
This method does not report which of these caused the * method to return. Callers should re-check the conditions which caused * the thread to park in the first place. Callers may also determine, * for example, the interrupt status of the thread upon return. */ public static void park() { unsafe.park(false, 0L); } /** * Disables the current thread for thread scheduling purposes, for up to * the specified waiting time, unless the permit is available. *
If the permit is available then it is consumed and the call returns * immediately; otherwise * the current thread becomes disabled for thread scheduling * purposes and lies dormant until one of four things happens: *
This method does not report which of these caused the * method to return. Callers should re-check the conditions which caused * the thread to park in the first place. Callers may also determine, * for example, the interrupt status of the thread, or the elapsed time * upon return. * * @param nanos the maximum number of nanoseconds to wait */ public static void parkNanos(long nanos) { if (nanos > 0) unsafe.park(false, nanos); } /** * Disables the current thread for thread scheduling purposes, until * the specified deadline, unless the permit is available. *
If the permit is available then it is consumed and the call returns * immediately; otherwise * the current thread becomes disabled for thread scheduling * purposes and lies dormant until one of four things happens: *
This method does not report which of these caused the * method to return. Callers should re-check the conditions which caused * the thread to park in the first place. Callers may also determine, * for example, the interrupt status of the thread, or the current time * upon return. * * @param deadline the absolute time, in milliseconds from the Epoch, to * wait until */ public static void parkUntil(long deadline) { unsafe.park(true, deadline); } }