Liking cljdoc? Tell your friends :D

jdk.util.concurrent.locks.AbstractOwnableSynchronizer

A synchronizer that may be exclusively owned by a thread. This class provides a basis for creating locks and related synchronizers that may entail a notion of ownership. The AbstractOwnableSynchronizer class itself does not manage or use this information. However, subclasses and tools may use appropriately maintained values to help control and monitor access and provide diagnostics.

A synchronizer that may be exclusively owned by a thread.  This
class provides a basis for creating locks and related synchronizers
that may entail a notion of ownership.  The
AbstractOwnableSynchronizer class itself does not manage or
use this information. However, subclasses and tools may use
appropriately maintained values to help control and monitor access
and provide diagnostics.
raw docstring

No vars found in this namespace.

jdk.util.concurrent.locks.AbstractQueuedLongSynchronizer

A version of AbstractQueuedSynchronizer in which synchronization state is maintained as a long. This class has exactly the same structure, properties, and methods as AbstractQueuedSynchronizer with the exception that all state-related parameters and results are defined as long rather than int. This class may be useful when creating synchronizers such as multilevel locks and barriers that require 64 bits of state.

See AbstractQueuedSynchronizer for usage notes and examples.

A version of AbstractQueuedSynchronizer in
which synchronization state is maintained as a long.
This class has exactly the same structure, properties, and methods
as AbstractQueuedSynchronizer with the exception
that all state-related parameters and results are defined
as long rather than int. This class
may be useful when creating synchronizers such as
multilevel locks and barriers that require
64 bits of state.

See AbstractQueuedSynchronizer for usage
notes and examples.
raw docstring

jdk.util.concurrent.locks.AbstractQueuedSynchronizer

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState(), setState(int) and compareAndSetState(int, int) is tracked with respect to synchronization.

Subclasses should be defined as non-public internal helper classes that are used to implement the synchronization properties of their enclosing class. Class AbstractQueuedSynchronizer does not implement any synchronization interface. Instead it defines methods such as acquireInterruptibly(int) that can be invoked as appropriate by concrete locks and related synchronizers to implement their public methods.

This class supports either or both a default exclusive mode and a shared mode. When acquired in exclusive mode, attempted acquires by other threads cannot succeed. Shared mode acquires by multiple threads may (but need not) succeed. This class does not "understand" these differences except in the mechanical sense that when a shared mode acquire succeeds, the next waiting thread (if one exists) must also determine whether it can acquire as well. Threads waiting in the different modes share the same FIFO queue. Usually, implementation subclasses support only one of these modes, but both can come into play for example in a ReadWriteLock. Subclasses that support only exclusive or only shared modes need not define the methods supporting the unused mode.

This class defines a nested AbstractQueuedSynchronizer.ConditionObject class that can be used as a Condition implementation by subclasses supporting exclusive mode for which method isHeldExclusively() reports whether synchronization is exclusively held with respect to the current thread, method release(int) invoked with the current getState() value fully releases this object, and acquire(int), given this saved state value, eventually restores this object to its previous acquired state. No AbstractQueuedSynchronizer method otherwise creates such a condition, so if this constraint cannot be met, do not use it. The behavior of AbstractQueuedSynchronizer.ConditionObject depends of course on the semantics of its synchronizer implementation.

This class provides inspection, instrumentation, and monitoring methods for the internal queue, as well as similar methods for condition objects. These can be exported as desired into classes using an AbstractQueuedSynchronizer for their synchronization mechanics.

Serialization of this class stores only the underlying atomic integer maintaining state, so deserialized objects have empty thread queues. Typical subclasses requiring serializability will define a readObject method that restores this to a known initial state upon deserialization.

Usage

To use this class as the basis of a synchronizer, redefine the following methods, as applicable, by inspecting and/or modifying the synchronization state using getState(), setState(int) and/or compareAndSetState(int, int):

tryAcquire(int) tryRelease(int) tryAcquireShared(int) tryReleaseShared(int) isHeldExclusively()

Each of these methods by default throws UnsupportedOperationException. Implementations of these methods must be internally thread-safe, and should in general be short and not block. Defining these methods is the only supported means of using this class. All other methods are declared final because they cannot be independently varied.

You may also find the inherited methods from AbstractOwnableSynchronizer useful to keep track of the thread owning an exclusive synchronizer. You are encouraged to use them -- this enables monitoring and diagnostic tools to assist users in determining which threads hold locks.

Even though this class is based on an internal FIFO queue, it does not automatically enforce FIFO acquisition policies. The core of exclusive synchronization takes the form:

Acquire: while (!tryAcquire(arg)) { enqueue thread if it is not already queued; possibly block current thread; }

Release: if (tryRelease(arg)) unblock the first queued thread;

(Shared mode is similar but may involve cascading signals.)

Because checks in acquire are invoked before enqueuing, a newly acquiring thread may barge ahead of others that are blocked and queued. However, you can, if desired, define tryAcquire and/or tryAcquireShared to disable barging by internally invoking one or more of the inspection methods, thereby providing a fair FIFO acquisition order. In particular, most fair synchronizers can define tryAcquire to return false if hasQueuedPredecessors() (a method specifically designed to be used by fair synchronizers) returns true. Other variations are possible.

Throughput and scalability are generally highest for the default barging (also known as greedy, renouncement, and convoy-avoidance) strategy. While this is not guaranteed to be fair or starvation-free, earlier queued threads are allowed to recontend before later queued threads, and each recontention has an unbiased chance to succeed against incoming threads. Also, while acquires do not "spin" in the usual sense, they may perform multiple invocations of tryAcquire interspersed with other computations before blocking. This gives most of the benefits of spins when exclusive synchronization is only briefly held, without most of the liabilities when it isn't. If so desired, you can augment this by preceding calls to acquire methods with "fast-path" checks, possibly prechecking hasContended() and/or hasQueuedThreads() to only do so if the synchronizer is likely not to be contended.

This class provides an efficient and scalable basis for synchronization in part by specializing its range of use to synchronizers that can rely on int state, acquire, and release parameters, and an internal FIFO wait queue. When this does not suffice, you can build synchronizers from a lower level using atomic classes, your own custom Queue classes, and LockSupport blocking support.

Usage Examples

Here is a non-reentrant mutual exclusion lock class that uses the value zero to represent the unlocked state, and one to represent the locked state. While a non-reentrant lock does not strictly require recording of the current owner thread, this class does so anyway to make usage easier to monitor. It also supports conditions and exposes one of the instrumentation methods:

class Mutex implements Lock, java.io.Serializable {

// Our internal helper class private static class Sync extends AbstractQueuedSynchronizer { // Reports whether in locked state protected boolean isHeldExclusively() { return getState() == 1; }

// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
  assert acquires == 1; // Otherwise unused
  if (compareAndSetState(0, 1)) {
    setExclusiveOwnerThread(Thread.currentThread());
    return true;
  }
  return false;
}

// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
  assert releases == 1; // Otherwise unused
  if (getState() == 0) throw new IllegalMonitorStateException();
  setExclusiveOwnerThread(null);
  setState(0);
  return true;
}

// Provides a Condition
Condition newCondition() { return new ConditionObject(); }

// Deserializes properly
private void readObject(ObjectInputStream s)
    throws IOException, ClassNotFoundException {
  s.defaultReadObject();
  setState(0); // reset to unlocked state
}

}

// The sync object does all the hard work. We just forward to it. private final Sync sync = new Sync();

public void lock() { sync.acquire(1); } public boolean tryLock() { return sync.tryAcquire(1); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } }

Here is a latch class that is like a CountDownLatch except that it only requires a single signal to fire. Because a latch is non-exclusive, it uses the shared acquire and release methods.

class BooleanLatch {

private static class Sync extends AbstractQueuedSynchronizer { boolean isSignalled() { return getState() != 0; }

protected int tryAcquireShared(int ignore) {
  return isSignalled() ? 1 : -1;
}

protected boolean tryReleaseShared(int ignore) {
  setState(1);
  return true;
}

}

private final Sync sync = new Sync(); public boolean isSignalled() { return sync.isSignalled(); } public void signal() { sync.releaseShared(1); } public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); } }

Provides a framework for implementing blocking locks and related
synchronizers (semaphores, events, etc) that rely on
first-in-first-out (FIFO) wait queues.  This class is designed to
be a useful basis for most kinds of synchronizers that rely on a
single atomic int value to represent state. Subclasses
must define the protected methods that change this state, and which
define what that state means in terms of this object being acquired
or released.  Given these, the other methods in this class carry
out all queuing and blocking mechanics. Subclasses can maintain
other state fields, but only the atomically updated int
value manipulated using methods getState(), setState(int) and compareAndSetState(int, int) is tracked with respect
to synchronization.

Subclasses should be defined as non-public internal helper
classes that are used to implement the synchronization properties
of their enclosing class.  Class
AbstractQueuedSynchronizer does not implement any
synchronization interface.  Instead it defines methods such as
acquireInterruptibly(int) that can be invoked as
appropriate by concrete locks and related synchronizers to
implement their public methods.

This class supports either or both a default exclusive
mode and a shared mode. When acquired in exclusive mode,
attempted acquires by other threads cannot succeed. Shared mode
acquires by multiple threads may (but need not) succeed. This class
does not "understand" these differences except in the
mechanical sense that when a shared mode acquire succeeds, the next
waiting thread (if one exists) must also determine whether it can
acquire as well. Threads waiting in the different modes share the
same FIFO queue. Usually, implementation subclasses support only
one of these modes, but both can come into play for example in a
ReadWriteLock. Subclasses that support only exclusive or
only shared modes need not define the methods supporting the unused mode.

This class defines a nested AbstractQueuedSynchronizer.ConditionObject class that
can be used as a Condition implementation by subclasses
supporting exclusive mode for which method isHeldExclusively() reports whether synchronization is exclusively
held with respect to the current thread, method release(int)
invoked with the current getState() value fully releases
this object, and acquire(int), given this saved state value,
eventually restores this object to its previous acquired state.  No
AbstractQueuedSynchronizer method otherwise creates such a
condition, so if this constraint cannot be met, do not use it.  The
behavior of AbstractQueuedSynchronizer.ConditionObject depends of course on the
semantics of its synchronizer implementation.

This class provides inspection, instrumentation, and monitoring
methods for the internal queue, as well as similar methods for
condition objects. These can be exported as desired into classes
using an AbstractQueuedSynchronizer for their
synchronization mechanics.

Serialization of this class stores only the underlying atomic
integer maintaining state, so deserialized objects have empty
thread queues. Typical subclasses requiring serializability will
define a readObject method that restores this to a known
initial state upon deserialization.

Usage

To use this class as the basis of a synchronizer, redefine the
following methods, as applicable, by inspecting and/or modifying
the synchronization state using getState(), setState(int) and/or compareAndSetState(int, int):


 tryAcquire(int)
 tryRelease(int)
 tryAcquireShared(int)
 tryReleaseShared(int)
 isHeldExclusively()


Each of these methods by default throws UnsupportedOperationException.  Implementations of these methods
must be internally thread-safe, and should in general be short and
not block. Defining these methods is the only supported
means of using this class. All other methods are declared
final because they cannot be independently varied.

You may also find the inherited methods from AbstractOwnableSynchronizer useful to keep track of the thread
owning an exclusive synchronizer.  You are encouraged to use them
-- this enables monitoring and diagnostic tools to assist users in
determining which threads hold locks.

Even though this class is based on an internal FIFO queue, it
does not automatically enforce FIFO acquisition policies.  The core
of exclusive synchronization takes the form:



Acquire:
    while (!tryAcquire(arg)) {
       enqueue thread if it is not already queued;
       possibly block current thread;
    }

Release:
    if (tryRelease(arg))
       unblock the first queued thread;

(Shared mode is similar but may involve cascading signals.)

Because checks in acquire are invoked before
enqueuing, a newly acquiring thread may barge ahead of
others that are blocked and queued.  However, you can, if desired,
define tryAcquire and/or tryAcquireShared to
disable barging by internally invoking one or more of the inspection
methods, thereby providing a fair FIFO acquisition order.
In particular, most fair synchronizers can define tryAcquire
to return false if hasQueuedPredecessors() (a method
specifically designed to be used by fair synchronizers) returns
true.  Other variations are possible.

Throughput and scalability are generally highest for the
default barging (also known as greedy,
renouncement, and convoy-avoidance) strategy.
While this is not guaranteed to be fair or starvation-free, earlier
queued threads are allowed to recontend before later queued
threads, and each recontention has an unbiased chance to succeed
against incoming threads.  Also, while acquires do not
"spin" in the usual sense, they may perform multiple
invocations of tryAcquire interspersed with other
computations before blocking.  This gives most of the benefits of
spins when exclusive synchronization is only briefly held, without
most of the liabilities when it isn't. If so desired, you can
augment this by preceding calls to acquire methods with
"fast-path" checks, possibly prechecking hasContended()
and/or hasQueuedThreads() to only do so if the synchronizer
is likely not to be contended.

This class provides an efficient and scalable basis for
synchronization in part by specializing its range of use to
synchronizers that can rely on int state, acquire, and
release parameters, and an internal FIFO wait queue. When this does
not suffice, you can build synchronizers from a lower level using
atomic classes, your own custom
Queue classes, and LockSupport blocking
support.

Usage Examples

Here is a non-reentrant mutual exclusion lock class that uses
the value zero to represent the unlocked state, and one to
represent the locked state. While a non-reentrant lock
does not strictly require recording of the current owner
thread, this class does so anyway to make usage easier to monitor.
It also supports conditions and exposes
one of the instrumentation methods:



class Mutex implements Lock, java.io.Serializable {

  // Our internal helper class
  private static class Sync extends AbstractQueuedSynchronizer {
    // Reports whether in locked state
    protected boolean isHeldExclusively() {
      return getState() == 1;
    }

    // Acquires the lock if state is zero
    public boolean tryAcquire(int acquires) {
      assert acquires == 1; // Otherwise unused
      if (compareAndSetState(0, 1)) {
        setExclusiveOwnerThread(Thread.currentThread());
        return true;
      }
      return false;
    }

    // Releases the lock by setting state to zero
    protected boolean tryRelease(int releases) {
      assert releases == 1; // Otherwise unused
      if (getState() == 0) throw new IllegalMonitorStateException();
      setExclusiveOwnerThread(null);
      setState(0);
      return true;
    }

    // Provides a Condition
    Condition newCondition() { return new ConditionObject(); }

    // Deserializes properly
    private void readObject(ObjectInputStream s)
        throws IOException, ClassNotFoundException {
      s.defaultReadObject();
      setState(0); // reset to unlocked state
    }
  }

  // The sync object does all the hard work. We just forward to it.
  private final Sync sync = new Sync();

  public void lock()                { sync.acquire(1); }
  public boolean tryLock()          { return sync.tryAcquire(1); }
  public void unlock()              { sync.release(1); }
  public Condition newCondition()   { return sync.newCondition(); }
  public boolean isLocked()         { return sync.isHeldExclusively(); }
  public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
  public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
  }
  public boolean tryLock(long timeout, TimeUnit unit)
      throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  }
}

Here is a latch class that is like a
CountDownLatch
except that it only requires a single signal to
fire. Because a latch is non-exclusive, it uses the shared
acquire and release methods.



class BooleanLatch {

  private static class Sync extends AbstractQueuedSynchronizer {
    boolean isSignalled() { return getState() != 0; }

    protected int tryAcquireShared(int ignore) {
      return isSignalled() ? 1 : -1;
    }

    protected boolean tryReleaseShared(int ignore) {
      setState(1);
      return true;
    }
  }

  private final Sync sync = new Sync();
  public boolean isSignalled() { return sync.isSignalled(); }
  public void signal()         { sync.releaseShared(1); }
  public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
  }
}
raw docstring

jdk.util.concurrent.locks.Condition

Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.

A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock instance use its newCondition() method.

As an example, suppose we have a bounded buffer which supports put and take methods. If a take is attempted on an empty buffer, then the thread will block until an item becomes available; if a put is attempted on a full buffer, then the thread will block until a space becomes available. We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer. This can be achieved using two Condition instances.

class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition();

final Object[] items = new Object[100]; int putptr, takeptr, count;

public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; +count; notEmpty.signal(); } finally { lock.unlock(); } }

public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }

(The ArrayBlockingQueue class provides this functionality, so there is no reason to implement this sample usage class.)

A Condition implementation can provide behavior and semantics that is different from that of the Object monitor methods, such as guaranteed ordering for notifications, or not requiring a lock to be held when performing notifications. If an implementation provides such specialized semantics then the implementation must document those semantics.

Note that Condition instances are just normal objects and can themselves be used as the target in a synchronized statement, and can have their own monitor wait and notification methods invoked. Acquiring the monitor lock of a Condition instance, or using its monitor methods, has no specified relationship with acquiring the Lock associated with that Condition or the use of its waiting and signalling methods. It is recommended that to avoid confusion you never use Condition instances in this way, except perhaps within their own implementation.

Except where noted, passing a null value for any parameter will result in a NullPointerException being thrown.

Implementation Considerations

When waiting upon a Condition, a "spurious wakeup" is permitted to occur, in general, as a concession to the underlying platform semantics. This has little practical impact on most application programs as a Condition should always be waited upon in a loop, testing the state predicate that is being waited for. An implementation is free to remove the possibility of spurious wakeups but it is recommended that applications programmers always assume that they can occur and so always wait in a loop.

The three forms of condition waiting (interruptible, non-interruptible, and timed) may differ in their ease of implementation on some platforms and in their performance characteristics. In particular, it may be difficult to provide these features and maintain specific semantics such as ordering guarantees. Further, the ability to interrupt the actual suspension of the thread may not always be feasible to implement on all platforms.

Consequently, an implementation is not required to define exactly the same guarantees or semantics for all three forms of waiting, nor is it required to support interruption of the actual suspension of the thread.

An implementation is required to clearly document the semantics and guarantees provided by each of the waiting methods, and when an implementation does support interruption of thread suspension then it must obey the interruption semantics as defined in this interface.

As interruption generally implies cancellation, and checks for interruption are often infrequent, an implementation can favor responding to an interrupt over normal method return. This is true even if it can be shown that the interrupt occurred after another action that may have unblocked the thread. An implementation should document this behavior.

Condition factors out the Object monitor
methods (wait, notify
and notifyAll) into distinct objects to
give the effect of having multiple wait-sets per object, by
combining them with the use of arbitrary Lock implementations.
Where a Lock replaces the use of synchronized methods
and statements, a Condition replaces the use of the Object
monitor methods.

Conditions (also known as condition queues or
condition variables) provide a means for one thread to
suspend execution (to "wait") until notified by another
thread that some state condition may now be true.  Because access
to this shared state information occurs in different threads, it
must be protected, so a lock of some form is associated with the
condition. The key property that waiting for a condition provides
is that it atomically releases the associated lock and
suspends the current thread, just like Object.wait.

A Condition instance is intrinsically bound to a lock.
To obtain a Condition instance for a particular Lock
instance use its newCondition() method.

As an example, suppose we have a bounded buffer which supports
put and take methods.  If a
take is attempted on an empty buffer, then the thread will block
until an item becomes available; if a put is attempted on a
full buffer, then the thread will block until a space becomes available.
We would like to keep waiting put threads and take
threads in separate wait-sets so that we can use the optimization of
only notifying a single thread at a time when items or spaces become
available in the buffer. This can be achieved using two
Condition instances.


class BoundedBuffer {
  final Lock lock = new ReentrantLock();
  final Condition notFull  = lock.newCondition();
  final Condition notEmpty = lock.newCondition();

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(Object x) throws InterruptedException {
    lock.lock();
    try {
      while (count == items.length)
        notFull.await();
      items[putptr] = x;
      if (++putptr == items.length) putptr = 0;
      +count;
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }

  public Object take() throws InterruptedException {
    lock.lock();
    try {
      while (count == 0)
        notEmpty.await();
      Object x = items[takeptr];
      if (++takeptr == items.length) takeptr = 0;
      --count;
      notFull.signal();
      return x;
    } finally {
      lock.unlock();
    }
  }
}

(The ArrayBlockingQueue class provides
this functionality, so there is no reason to implement this
sample usage class.)

A Condition implementation can provide behavior and semantics
that is
different from that of the Object monitor methods, such as
guaranteed ordering for notifications, or not requiring a lock to be held
when performing notifications.
If an implementation provides such specialized semantics then the
implementation must document those semantics.

Note that Condition instances are just normal objects and can
themselves be used as the target in a synchronized statement,
and can have their own monitor wait and
notification methods invoked.
Acquiring the monitor lock of a Condition instance, or using its
monitor methods, has no specified relationship with acquiring the
Lock associated with that Condition or the use of its
waiting and signalling methods.
It is recommended that to avoid confusion you never use Condition
instances in this way, except perhaps within their own implementation.

Except where noted, passing a null value for any parameter
will result in a NullPointerException being thrown.

Implementation Considerations

When waiting upon a Condition, a "spurious
wakeup" is permitted to occur, in
general, as a concession to the underlying platform semantics.
This has little practical impact on most application programs as a
Condition should always be waited upon in a loop, testing
the state predicate that is being waited for.  An implementation is
free to remove the possibility of spurious wakeups but it is
recommended that applications programmers always assume that they can
occur and so always wait in a loop.

The three forms of condition waiting
(interruptible, non-interruptible, and timed) may differ in their ease of
implementation on some platforms and in their performance characteristics.
In particular, it may be difficult to provide these features and maintain
specific semantics such as ordering guarantees.
Further, the ability to interrupt the actual suspension of the thread may
not always be feasible to implement on all platforms.

Consequently, an implementation is not required to define exactly the
same guarantees or semantics for all three forms of waiting, nor is it
required to support interruption of the actual suspension of the thread.

An implementation is required to
clearly document the semantics and guarantees provided by each of the
waiting methods, and when an implementation does support interruption of
thread suspension then it must obey the interruption semantics as defined
in this interface.

As interruption generally implies cancellation, and checks for
interruption are often infrequent, an implementation can favor responding
to an interrupt over normal method return. This is true even if it can be
shown that the interrupt occurred after another action that may have
unblocked the thread. An implementation should document this behavior.
raw docstring

jdk.util.concurrent.locks.core

No vars found in this namespace.

jdk.util.concurrent.locks.Lock

Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects.

A lock is a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock.

The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired.

While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way. For example, some algorithms for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.

With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used:

Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }

When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.

Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).

A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection. If an implementation provides such specialized semantics then the implementation must document those semantics.

Note that Lock instances are just normal objects and can themselves be used as the target in a synchronized statement. Acquiring the monitor lock of a Lock instance has no specified relationship with invoking any of the lock() methods of that instance. It is recommended that to avoid confusion you never use Lock instances in this way, except within their own implementation.

Except where noted, passing a null value for any parameter will result in a NullPointerException being thrown.

Memory Synchronization

All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in

The Java Language Specification (17.4 Memory Model):

A successful lock operation has the same memory synchronization effects as a successful Lock action. A successful unlock operation has the same memory synchronization effects as a successful Unlock action.

Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.

Implementation Considerations

The three forms of lock acquisition (interruptible, non-interruptible, and timed) may differ in their performance characteristics, ordering guarantees, or other implementation qualities. Further, the ability to interrupt the ongoing acquisition of a lock may not be available in a given Lock class. Consequently, an implementation is not required to define exactly the same guarantees or semantics for all three forms of lock acquisition, nor is it required to support interruption of an ongoing lock acquisition. An implementation is required to clearly document the semantics and guarantees provided by each of the locking methods. It must also obey the interruption semantics as defined in this interface, to the extent that interruption of lock acquisition is supported: which is either totally, or only on method entry.

As interruption generally implies cancellation, and checks for interruption are often infrequent, an implementation can favor responding to an interrupt over normal method return. This is true even if it can be shown that the interrupt occurred after another action may have unblocked the thread. An implementation should document this behavior.

Lock implementations provide more extensive locking
operations than can be obtained using synchronized methods
and statements.  They allow more flexible structuring, may have
quite different properties, and may support multiple associated
Condition objects.

A lock is a tool for controlling access to a shared resource by
multiple threads. Commonly, a lock provides exclusive access to a
shared resource: only one thread at a time can acquire the lock and
all access to the shared resource requires that the lock be
acquired first. However, some locks may allow concurrent access to
a shared resource, such as the read lock of a ReadWriteLock.

The use of synchronized methods or statements provides
access to the implicit monitor lock associated with every object, but
forces all lock acquisition and release to occur in a block-structured way:
when multiple locks are acquired they must be released in the opposite
order, and all locks must be released in the same lexical scope in which
they were acquired.

While the scoping mechanism for synchronized methods
and statements makes it much easier to program with monitor locks,
and helps avoid many common programming errors involving locks,
there are occasions where you need to work with locks in a more
flexible way. For example, some algorithms for traversing
concurrently accessed data structures require the use of
"hand-over-hand" or "chain locking": you
acquire the lock of node A, then node B, then release A and acquire
C, then release B and acquire D and so on.  Implementations of the
Lock interface enable the use of such techniques by
allowing a lock to be acquired and released in different scopes,
and allowing multiple locks to be acquired and released in any
order.

With this increased flexibility comes additional
responsibility. The absence of block-structured locking removes the
automatic release of locks that occurs with synchronized
methods and statements. In most cases, the following idiom
should be used:



Lock l = ...;
l.lock();
try {
  // access the resource protected by this lock
} finally {
  l.unlock();
}

When locking and unlocking occur in different scopes, care must be
taken to ensure that all code that is executed while the lock is
held is protected by try-finally or try-catch to ensure that the
lock is released when necessary.

Lock implementations provide additional functionality
over the use of synchronized methods and statements by
providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be
interrupted (lockInterruptibly(), and an attempt to acquire
the lock that can timeout (tryLock(long, TimeUnit)).

A Lock class can also provide behavior and semantics
that is quite different from that of the implicit monitor lock,
such as guaranteed ordering, non-reentrant usage, or deadlock
detection. If an implementation provides such specialized semantics
then the implementation must document those semantics.

Note that Lock instances are just normal objects and can
themselves be used as the target in a synchronized statement.
Acquiring the
monitor lock of a Lock instance has no specified relationship
with invoking any of the lock() methods of that instance.
It is recommended that to avoid confusion you never use Lock
instances in this way, except within their own implementation.

Except where noted, passing a null value for any
parameter will result in a NullPointerException being
thrown.

Memory Synchronization

All Lock implementations must enforce the same
memory synchronization semantics as provided by the built-in monitor
lock, as described in

The Java Language Specification (17.4 Memory Model):

A successful lock operation has the same memory
synchronization effects as a successful Lock action.
A successful unlock operation has the same
memory synchronization effects as a successful Unlock action.


Unsuccessful locking and unlocking operations, and reentrant
locking/unlocking operations, do not require any memory
synchronization effects.

Implementation Considerations

The three forms of lock acquisition (interruptible,
non-interruptible, and timed) may differ in their performance
characteristics, ordering guarantees, or other implementation
qualities.  Further, the ability to interrupt the ongoing
acquisition of a lock may not be available in a given Lock
class.  Consequently, an implementation is not required to define
exactly the same guarantees or semantics for all three forms of
lock acquisition, nor is it required to support interruption of an
ongoing lock acquisition.  An implementation is required to clearly
document the semantics and guarantees provided by each of the
locking methods. It must also obey the interruption semantics as
defined in this interface, to the extent that interruption of lock
acquisition is supported: which is either totally, or only on
method entry.

As interruption generally implies cancellation, and checks for
interruption are often infrequent, an implementation can favor responding
to an interrupt over normal method return. This is true even if it can be
shown that the interrupt occurred after another action may have unblocked
the thread. An implementation should document this behavior.
raw docstring

jdk.util.concurrent.locks.LockSupport

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 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.

The three forms of park each also support a blocker object parameter. This object is recorded while the thread is blocked to permit monitoring and diagnostic tools to identify the reasons that threads are blocked. (Such tools may access blockers using method getBlocker(Thread).) The use of these forms rather than the original forms without this parameter is strongly encouraged. The normal argument to supply as a blocker within a lock implementation is this.

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. The park method is designed for use only in constructions of the form:

while (!canProceed()) { ... LockSupport.park(this); }

where neither canProceed nor any other actions prior to the call to park entail locking or blocking. Because only one permit is associated with each thread, any intermediary uses of park could interfere with its intended effects.

Sample Usage. Here is a sketch of a first-in-first-out non-reentrant lock class:

class FIFOMutex { private final AtomicBoolean locked = new AtomicBoolean(false); private final 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(this);
  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()); } }

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 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.

The three forms of park each also support a
blocker object parameter. This object is recorded while
the thread is blocked to permit monitoring and diagnostic tools to
identify the reasons that threads are blocked. (Such tools may
access blockers using method getBlocker(Thread).)
The use of these forms rather than the original forms without this
parameter is strongly encouraged. The normal argument to supply as
a blocker within a lock implementation is this.

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.  The park
method is designed for use only in constructions of the form:



while (!canProceed()) { ... LockSupport.park(this); }

where neither canProceed nor any other actions prior to the
call to park entail locking or blocking.  Because only one
permit is associated with each thread, any intermediary uses of
park could interfere with its intended effects.

Sample Usage. Here is a sketch of a first-in-first-out
non-reentrant lock class:


class FIFOMutex {
  private final AtomicBoolean locked = new AtomicBoolean(false);
  private final 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(this);
      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());
  }
}
raw docstring

jdk.util.concurrent.locks.ReadWriteLock

A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.

All ReadWriteLock implementations must guarantee that the memory synchronization effects of writeLock operations (as specified in the Lock interface) also hold with respect to the associated readLock. That is, a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock.

A read-write lock allows for a greater level of concurrency in accessing shared data than that permitted by a mutual exclusion lock. It exploits the fact that while only a single thread at a time (a writer thread) can modify the shared data, in many cases any number of threads can concurrently read the data (hence reader threads). In theory, the increase in concurrency permitted by the use of a read-write lock will lead to performance improvements over the use of a mutual exclusion lock. In practice this increase in concurrency will only be fully realized on a multi-processor, and then only if the access patterns for the shared data are suitable.

Whether or not a read-write lock will improve performance over the use of a mutual exclusion lock depends on the frequency that the data is read compared to being modified, the duration of the read and write operations, and the contention for the data - that is, the number of threads that will try to read or write the data at the same time. For example, a collection that is initially populated with data and thereafter infrequently modified, while being frequently searched (such as a directory of some kind) is an ideal candidate for the use of a read-write lock. However, if updates become frequent then the data spends most of its time being exclusively locked and there is little, if any increase in concurrency. Further, if the read operations are too short the overhead of the read-write lock implementation (which is inherently more complex than a mutual exclusion lock) can dominate the execution cost, particularly as many read-write lock implementations still serialize all threads through a small section of code. Ultimately, only profiling and measurement will establish whether the use of a read-write lock is suitable for your application.

Although the basic operation of a read-write lock is straight-forward, there are many policy decisions that an implementation must make, which may affect the effectiveness of the read-write lock in a given application. Examples of these policies include:

Determining whether to grant the read lock or the write lock, when both readers and writers are waiting, at the time that a writer releases the write lock. Writer preference is common, as writes are expected to be short and infrequent. Reader preference is less common as it can lead to lengthy delays for a write if the readers are frequent and long-lived as expected. Fair, or "in-order" implementations are also possible.

Determining whether readers that request the read lock while a reader is active and a writer is waiting, are granted the read lock. Preference to the reader can delay the writer indefinitely, while preference to the writer can reduce the potential for concurrency.

Determining whether the locks are reentrant: can a thread with the write lock reacquire it? Can it acquire a read lock while holding the write lock? Is the read lock itself reentrant?

Can the write lock be downgraded to a read lock without allowing an intervening writer? Can a read lock be upgraded to a write lock, in preference to other waiting readers or writers?

You should consider all of these things when evaluating the suitability of a given implementation for your application.

A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing.
The read lock may be held simultaneously by
multiple reader threads, so long as there are no writers.  The
write lock is exclusive.

All ReadWriteLock implementations must guarantee that
the memory synchronization effects of writeLock operations
(as specified in the Lock interface) also hold with respect
to the associated readLock. That is, a thread successfully
acquiring the read lock will see all updates made upon previous
release of the write lock.

A read-write lock allows for a greater level of concurrency in
accessing shared data than that permitted by a mutual exclusion lock.
It exploits the fact that while only a single thread at a time (a
writer thread) can modify the shared data, in many cases any
number of threads can concurrently read the data (hence reader
threads).
In theory, the increase in concurrency permitted by the use of a read-write
lock will lead to performance improvements over the use of a mutual
exclusion lock. In practice this increase in concurrency will only be fully
realized on a multi-processor, and then only if the access patterns for
the shared data are suitable.

Whether or not a read-write lock will improve performance over the use
of a mutual exclusion lock depends on the frequency that the data is
read compared to being modified, the duration of the read and write
operations, and the contention for the data - that is, the number of
threads that will try to read or write the data at the same time.
For example, a collection that is initially populated with data and
thereafter infrequently modified, while being frequently searched
(such as a directory of some kind) is an ideal candidate for the use of
a read-write lock. However, if updates become frequent then the data
spends most of its time being exclusively locked and there is little, if any
increase in concurrency. Further, if the read operations are too short
the overhead of the read-write lock implementation (which is inherently
more complex than a mutual exclusion lock) can dominate the execution
cost, particularly as many read-write lock implementations still serialize
all threads through a small section of code. Ultimately, only profiling
and measurement will establish whether the use of a read-write lock is
suitable for your application.


Although the basic operation of a read-write lock is straight-forward,
there are many policy decisions that an implementation must make, which
may affect the effectiveness of the read-write lock in a given application.
Examples of these policies include:

Determining whether to grant the read lock or the write lock, when
both readers and writers are waiting, at the time that a writer releases
the write lock. Writer preference is common, as writes are expected to be
short and infrequent. Reader preference is less common as it can lead to
lengthy delays for a write if the readers are frequent and long-lived as
expected. Fair, or "in-order" implementations are also possible.

Determining whether readers that request the read lock while a
reader is active and a writer is waiting, are granted the read lock.
Preference to the reader can delay the writer indefinitely, while
preference to the writer can reduce the potential for concurrency.

Determining whether the locks are reentrant: can a thread with the
write lock reacquire it? Can it acquire a read lock while holding the
write lock? Is the read lock itself reentrant?

Can the write lock be downgraded to a read lock without allowing
an intervening writer? Can a read lock be upgraded to a write lock,
in preference to other waiting readers or writers?


You should consider all of these things when evaluating the suitability
of a given implementation for your application.
raw docstring

jdk.util.concurrent.locks.ReentrantLock

A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.

A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock. This can be checked using methods isHeldByCurrentThread(), and getHoldCount().

The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. Note however, that fairness of locks does not guarantee fairness of thread scheduling. Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. Also note that the untimed tryLock() method does not honor the fairness setting. It will succeed if the lock is available even if other threads are waiting.

It is recommended practice to always immediately follow a call to lock with a try block, most typically in a before/after construction such as:

class X { private final ReentrantLock lock = new ReentrantLock(); // ...

public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }

In addition to implementing the Lock interface, this class defines a number of public and protected methods for inspecting the state of the lock. Some of these methods are only useful for instrumentation and monitoring.

Serialization of this class behaves in the same way as built-in locks: a deserialized lock is in the unlocked state, regardless of its state when serialized.

This lock supports a maximum of 2147483647 recursive locks by the same thread. Attempts to exceed this limit result in Error throws from locking methods.

A reentrant mutual exclusion Lock with the same basic
behavior and semantics as the implicit monitor lock accessed using
synchronized methods and statements, but with extended
capabilities.

A ReentrantLock is owned by the thread last
successfully locking, but not yet unlocking it. A thread invoking
lock will return, successfully acquiring the lock, when
the lock is not owned by another thread. The method will return
immediately if the current thread already owns the lock. This can
be checked using methods isHeldByCurrentThread(), and getHoldCount().

The constructor for this class accepts an optional
fairness parameter.  When set true, under
contention, locks favor granting access to the longest-waiting
thread.  Otherwise this lock does not guarantee any particular
access order.  Programs using fair locks accessed by many threads
may display lower overall throughput (i.e., are slower; often much
slower) than those using the default setting, but have smaller
variances in times to obtain locks and guarantee lack of
starvation. Note however, that fairness of locks does not guarantee
fairness of thread scheduling. Thus, one of many threads using a
fair lock may obtain it multiple times in succession while other
active threads are not progressing and not currently holding the
lock.
Also note that the untimed tryLock() method does not
honor the fairness setting. It will succeed if the lock
is available even if other threads are waiting.

It is recommended practice to always immediately
follow a call to lock with a try block, most
typically in a before/after construction such as:



class X {
  private final ReentrantLock lock = new ReentrantLock();
  // ...

  public void m() {
    lock.lock();  // block until condition holds
    try {
      // ... method body
    } finally {
      lock.unlock()
    }
  }
}

In addition to implementing the Lock interface, this
class defines a number of public and protected
methods for inspecting the state of the lock.  Some of these
methods are only useful for instrumentation and monitoring.

Serialization of this class behaves in the same way as built-in
locks: a deserialized lock is in the unlocked state, regardless of
its state when serialized.

This lock supports a maximum of 2147483647 recursive locks by
the same thread. Attempts to exceed this limit result in
Error throws from locking methods.
raw docstring

jdk.util.concurrent.locks.ReentrantReadWriteLock

An implementation of ReadWriteLock supporting similar semantics to ReentrantLock. This class has the following properties:

Acquisition order

This class does not impose a reader or writer preference ordering for lock access. However, it does support an optional fairness policy.

Non-fair mode (default) When constructed as non-fair (the default), the order of entry to the read and write lock is unspecified, subject to reentrancy constraints. A nonfair lock that is continuously contended may indefinitely postpone one or more reader or writer threads, but will normally have higher throughput than a fair lock.

Fair mode When constructed as fair, threads contend for entry using an approximately arrival-order policy. When the currently held lock is released, either the longest-waiting single writer thread will be assigned the write lock, or if there is a group of reader threads waiting longer than all waiting writer threads, that group will be assigned the read lock.

A thread that tries to acquire a fair read lock (non-reentrantly) will block if either the write lock is held, or there is a waiting writer thread. The thread will not acquire the read lock until after the oldest currently waiting writer thread has acquired and released the write lock. Of course, if a waiting writer abandons its wait, leaving one or more reader threads as the longest waiters in the queue with the write lock free, then those readers will be assigned the read lock.

A thread that tries to acquire a fair write lock (non-reentrantly) will block unless both the read lock and write lock are free (which implies there are no waiting threads). (Note that the non-blocking ReentrantReadWriteLock.ReadLock.tryLock() and ReentrantReadWriteLock.WriteLock.tryLock() methods do not honor this fair setting and will immediately acquire the lock if it is possible, regardless of waiting threads.)

Reentrancy

This lock allows both readers and writers to reacquire read or write locks in the style of a ReentrantLock. Non-reentrant readers are not allowed until all write locks held by the writing thread have been released.

Additionally, a writer can acquire the read lock, but not vice-versa. Among other applications, reentrancy can be useful when write locks are held during calls or callbacks to methods that perform reads under read locks. If a reader tries to acquire the write lock it will never succeed.

Lock downgrading Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible.

Interruption of lock acquisition The read lock and write lock both support interruption during lock acquisition.

Condition support The write lock provides a Condition implementation that behaves in the same way, with respect to the write lock, as the Condition implementation provided by ReentrantLock.newCondition() does for ReentrantLock. This Condition can, of course, only be used with the write lock.

The read lock does not support a Condition and readLock().newCondition() throws UnsupportedOperationException.

Instrumentation This class supports methods to determine whether locks are held or contended. These methods are designed for monitoring system state, not for synchronization control.

Serialization of this class behaves in the same way as built-in locks: a deserialized lock is in the unlocked state, regardless of its state when serialized.

Sample usages. Here is a code sketch showing how to perform lock downgrading after updating a cache (exception handling is particularly tricky when handling multiple locks in a non-nested fashion):

class CachedData { Object data; volatile boolean cacheValid; final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

void processCachedData() { rwl.readLock().lock(); if (!cacheValid) { // Must release read lock before acquiring write lock rwl.readLock().unlock(); rwl.writeLock().lock(); try { // Recheck state because another thread might have // acquired write lock and changed state before we did. if (!cacheValid) { data = ... cacheValid = true; } // Downgrade by acquiring read lock before releasing write lock rwl.readLock().lock(); } finally { rwl.writeLock().unlock(); // Unlock write, still hold read } }

try {
  use(data);
} finally {
  rwl.readLock().unlock();
}

} }

ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. This is typically worthwhile only when the collections are expected to be large, accessed by more reader threads than writer threads, and entail operations with overhead that outweighs synchronization overhead. For example, here is a class using a TreeMap that is expected to be large and concurrently accessed.

class RWDictionary { private final Map<String, Data> m = new TreeMap<String, Data>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock();

public Data get(String key) { r.lock(); try { return m.get(key); } finally { r.unlock(); } } public String[] allKeys() { r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); } } public Data put(String key, Data value) { w.lock(); try { return m.put(key, value); } finally { w.unlock(); } } public void clear() { w.lock(); try { m.clear(); } finally { w.unlock(); } } }

Implementation Notes

This lock supports a maximum of 65535 recursive write locks and 65535 read locks. Attempts to exceed these limits result in Error throws from locking methods.

An implementation of ReadWriteLock supporting similar
semantics to ReentrantLock.
This class has the following properties:


Acquisition order

This class does not impose a reader or writer preference
ordering for lock access.  However, it does support an optional
fairness policy.


Non-fair mode (default)
When constructed as non-fair (the default), the order of entry
to the read and write lock is unspecified, subject to reentrancy
constraints.  A nonfair lock that is continuously contended may
indefinitely postpone one or more reader or writer threads, but
will normally have higher throughput than a fair lock.

Fair mode
When constructed as fair, threads contend for entry using an
approximately arrival-order policy. When the currently held lock
is released, either the longest-waiting single writer thread will
be assigned the write lock, or if there is a group of reader threads
waiting longer than all waiting writer threads, that group will be
assigned the read lock.

A thread that tries to acquire a fair read lock (non-reentrantly)
will block if either the write lock is held, or there is a waiting
writer thread. The thread will not acquire the read lock until
after the oldest currently waiting writer thread has acquired and
released the write lock. Of course, if a waiting writer abandons
its wait, leaving one or more reader threads as the longest waiters
in the queue with the write lock free, then those readers will be
assigned the read lock.

A thread that tries to acquire a fair write lock (non-reentrantly)
will block unless both the read lock and write lock are free (which
implies there are no waiting threads).  (Note that the non-blocking
ReentrantReadWriteLock.ReadLock.tryLock() and ReentrantReadWriteLock.WriteLock.tryLock() methods
do not honor this fair setting and will immediately acquire the lock
if it is possible, regardless of waiting threads.)



Reentrancy

This lock allows both readers and writers to reacquire read or
write locks in the style of a ReentrantLock. Non-reentrant
readers are not allowed until all write locks held by the writing
thread have been released.

Additionally, a writer can acquire the read lock, but not
vice-versa.  Among other applications, reentrancy can be useful
when write locks are held during calls or callbacks to methods that
perform reads under read locks.  If a reader tries to acquire the
write lock it will never succeed.

Lock downgrading
Reentrancy also allows downgrading from the write lock to a read lock,
by acquiring the write lock, then the read lock and then releasing the
write lock. However, upgrading from a read lock to the write lock is
not possible.

Interruption of lock acquisition
The read lock and write lock both support interruption during lock
acquisition.

Condition support
The write lock provides a Condition implementation that
behaves in the same way, with respect to the write lock, as the
Condition implementation provided by
ReentrantLock.newCondition() does for ReentrantLock.
This Condition can, of course, only be used with the write lock.

The read lock does not support a Condition and
readLock().newCondition() throws
UnsupportedOperationException.

Instrumentation
This class supports methods to determine whether locks
are held or contended. These methods are designed for monitoring
system state, not for synchronization control.


Serialization of this class behaves in the same way as built-in
locks: a deserialized lock is in the unlocked state, regardless of
its state when serialized.

Sample usages. Here is a code sketch showing how to perform
lock downgrading after updating a cache (exception handling is
particularly tricky when handling multiple locks in a non-nested
fashion):



class CachedData {
  Object data;
  volatile boolean cacheValid;
  final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

  void processCachedData() {
    rwl.readLock().lock();
    if (!cacheValid) {
      // Must release read lock before acquiring write lock
      rwl.readLock().unlock();
      rwl.writeLock().lock();
      try {
        // Recheck state because another thread might have
        // acquired write lock and changed state before we did.
        if (!cacheValid) {
          data = ...
          cacheValid = true;
        }
        // Downgrade by acquiring read lock before releasing write lock
        rwl.readLock().lock();
      } finally {
        rwl.writeLock().unlock(); // Unlock write, still hold read
      }
    }

    try {
      use(data);
    } finally {
      rwl.readLock().unlock();
    }
  }
}

ReentrantReadWriteLocks can be used to improve concurrency in some
uses of some kinds of Collections. This is typically worthwhile
only when the collections are expected to be large, accessed by
more reader threads than writer threads, and entail operations with
overhead that outweighs synchronization overhead. For example, here
is a class using a TreeMap that is expected to be large and
concurrently accessed.



class RWDictionary {
  private final Map<String, Data> m = new TreeMap<String, Data>();
  private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  private final Lock r = rwl.readLock();
  private final Lock w = rwl.writeLock();

  public Data get(String key) {
    r.lock();
    try { return m.get(key); }
    finally { r.unlock(); }
  }
  public String[] allKeys() {
    r.lock();
    try { return m.keySet().toArray(); }
    finally { r.unlock(); }
  }
  public Data put(String key, Data value) {
    w.lock();
    try { return m.put(key, value); }
    finally { w.unlock(); }
  }
  public void clear() {
    w.lock();
    try { m.clear(); }
    finally { w.unlock(); }
  }
}

Implementation Notes

This lock supports a maximum of 65535 recursive write locks
and 65535 read locks. Attempts to exceed these limits result in
Error throws from locking methods.
raw docstring

jdk.util.concurrent.locks.ReentrantReadWriteLock$ReadLock

The lock returned by method ReentrantReadWriteLock.readLock().

The lock returned by method ReentrantReadWriteLock.readLock().
raw docstring

jdk.util.concurrent.locks.ReentrantReadWriteLock$WriteLock

The lock returned by method ReentrantReadWriteLock.writeLock().

The lock returned by method ReentrantReadWriteLock.writeLock().
raw docstring

jdk.util.concurrent.locks.StampedLock

A capability-based lock with three modes for controlling read/write access. The state of a StampedLock consists of a version and mode. Lock acquisition methods return a stamp that represents and controls access with respect to a lock state; "try" versions of these methods may instead return the special value zero to represent failure to acquire access. Lock release and conversion methods require stamps as arguments, and fail if they do not match the state of the lock. The three modes are:

Writing. Method writeLock() possibly blocks waiting for exclusive access, returning a stamp that can be used in method unlockWrite(long) to release the lock. Untimed and timed versions of tryWriteLock are also provided. When the lock is held in write mode, no read locks may be obtained, and all optimistic read validations will fail.

Reading. Method readLock() possibly blocks waiting for non-exclusive access, returning a stamp that can be used in method unlockRead(long) to release the lock. Untimed and timed versions of tryReadLock are also provided.

Optimistic Reading. Method tryOptimisticRead() returns a non-zero stamp only if the lock is not currently held in write mode. Method validate(long) returns true if the lock has not been acquired in write mode since obtaining a given stamp. This mode can be thought of as an extremely weak version of a read-lock, that can be broken by a writer at any time. The use of optimistic mode for short read-only code segments often reduces contention and improves throughput. However, its use is inherently fragile. Optimistic read sections should only read fields and hold them in local variables for later use after validation. Fields read while in optimistic mode may be wildly inconsistent, so usage applies only when you are familiar enough with data representations to check consistency and/or repeatedly invoke method validate(). For example, such steps are typically required when first reading an object or array reference, and then accessing one of its fields, elements or methods.

This class also supports methods that conditionally provide conversions across the three modes. For example, method tryConvertToWriteLock(long) attempts to "upgrade" a mode, returning a valid write stamp if (1) already in writing mode (2) in reading mode and there are no other readers or (3) in optimistic mode and the lock is available. The forms of these methods are designed to help reduce some of the code bloat that otherwise occurs in retry-based designs.

StampedLocks are designed for use as internal utilities in the development of thread-safe components. Their use relies on knowledge of the internal properties of the data, objects, and methods they are protecting. They are not reentrant, so locked bodies should not call other unknown methods that may try to re-acquire locks (although you may pass a stamp to other methods that can use or convert it). The use of read lock modes relies on the associated code sections being side-effect-free. Unvalidated optimistic read sections cannot call methods that are not known to tolerate potential inconsistencies. Stamps use finite representations, and are not cryptographically secure (i.e., a valid stamp may be guessable). Stamp values may recycle after (no sooner than) one year of continuous operation. A stamp held without use or validation for longer than this period may fail to validate correctly. StampedLocks are serializable, but always deserialize into initial unlocked state, so they are not useful for remote locking.

The scheduling policy of StampedLock does not consistently prefer readers over writers or vice versa. All "try" methods are best-effort and do not necessarily conform to any scheduling or fairness policy. A zero return from any "try" method for acquiring or converting locks does not carry any information about the state of the lock; a subsequent invocation may succeed.

Because it supports coordinated usage across multiple lock modes, this class does not directly implement the Lock or ReadWriteLock interfaces. However, a StampedLock may be viewed asReadLock(), asWriteLock(), or asReadWriteLock() in applications requiring only the associated set of functionality.

Sample Usage. The following illustrates some usage idioms in a class that maintains simple two-dimensional points. The sample code illustrates some try/catch conventions even though they are not strictly needed here because no exceptions can occur in their bodies.

class Point { private double x, y; private final StampedLock sl = new StampedLock();

void move(double deltaX, double deltaY) { // an exclusively locked method long stamp = sl.writeLock(); try { x = deltaX; y = deltaY; } finally { sl.unlockWrite(stamp); } }

double distanceFromOrigin() { // A read-only method long stamp = sl.tryOptimisticRead(); double currentX = x, currentY = y; if (!sl.validate(stamp)) { stamp = sl.readLock(); try { currentX = x; currentY = y; } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX currentY * currentY); }

void moveIfAtOrigin(double newX, double newY) { // upgrade // Could instead start with optimistic, not read mode long stamp = sl.readLock(); try { while (x == 0.0 && y == 0.0) { long ws = sl.tryConvertToWriteLock(stamp); if (ws != 0L) { stamp = ws; x = newX; y = newY; break; } else { sl.unlockRead(stamp); stamp = sl.writeLock(); } } } finally { sl.unlock(stamp); } } }

A capability-based lock with three modes for controlling read/write
access.  The state of a StampedLock consists of a version and mode.
Lock acquisition methods return a stamp that represents and
controls access with respect to a lock state; "try" versions of
these methods may instead return the special value zero to
represent failure to acquire access. Lock release and conversion
methods require stamps as arguments, and fail if they do not match
the state of the lock. The three modes are:



 Writing. Method writeLock() possibly blocks
  waiting for exclusive access, returning a stamp that can be used
  in method unlockWrite(long) to release the lock. Untimed and
  timed versions of tryWriteLock are also provided. When
  the lock is held in write mode, no read locks may be obtained,
  and all optimistic read validations will fail.

 Reading. Method readLock() possibly blocks
  waiting for non-exclusive access, returning a stamp that can be
  used in method unlockRead(long) to release the lock. Untimed
  and timed versions of tryReadLock are also provided.

 Optimistic Reading. Method tryOptimisticRead()
  returns a non-zero stamp only if the lock is not currently held
  in write mode. Method validate(long) returns true if the lock
  has not been acquired in write mode since obtaining a given
  stamp.  This mode can be thought of as an extremely weak version
  of a read-lock, that can be broken by a writer at any time.  The
  use of optimistic mode for short read-only code segments often
  reduces contention and improves throughput.  However, its use is
  inherently fragile.  Optimistic read sections should only read
  fields and hold them in local variables for later use after
  validation. Fields read while in optimistic mode may be wildly
  inconsistent, so usage applies only when you are familiar enough
  with data representations to check consistency and/or repeatedly
  invoke method validate().  For example, such steps are
  typically required when first reading an object or array
  reference, and then accessing one of its fields, elements or
  methods.



This class also supports methods that conditionally provide
conversions across the three modes. For example, method tryConvertToWriteLock(long) attempts to "upgrade" a mode, returning
a valid write stamp if (1) already in writing mode (2) in reading
mode and there are no other readers or (3) in optimistic mode and
the lock is available. The forms of these methods are designed to
help reduce some of the code bloat that otherwise occurs in
retry-based designs.

StampedLocks are designed for use as internal utilities in the
development of thread-safe components. Their use relies on
knowledge of the internal properties of the data, objects, and
methods they are protecting.  They are not reentrant, so locked
bodies should not call other unknown methods that may try to
re-acquire locks (although you may pass a stamp to other methods
that can use or convert it).  The use of read lock modes relies on
the associated code sections being side-effect-free.  Unvalidated
optimistic read sections cannot call methods that are not known to
tolerate potential inconsistencies.  Stamps use finite
representations, and are not cryptographically secure (i.e., a
valid stamp may be guessable). Stamp values may recycle after (no
sooner than) one year of continuous operation. A stamp held without
use or validation for longer than this period may fail to validate
correctly.  StampedLocks are serializable, but always deserialize
into initial unlocked state, so they are not useful for remote
locking.

The scheduling policy of StampedLock does not consistently
prefer readers over writers or vice versa.  All "try" methods are
best-effort and do not necessarily conform to any scheduling or
fairness policy. A zero return from any "try" method for acquiring
or converting locks does not carry any information about the state
of the lock; a subsequent invocation may succeed.

Because it supports coordinated usage across multiple lock
modes, this class does not directly implement the Lock or
ReadWriteLock interfaces. However, a StampedLock may be
viewed asReadLock(), asWriteLock(), or asReadWriteLock() in applications requiring only the associated
set of functionality.

Sample Usage. The following illustrates some usage idioms
in a class that maintains simple two-dimensional points. The sample
code illustrates some try/catch conventions even though they are
not strictly needed here because no exceptions can occur in their
bodies.



class Point {
  private double x, y;
  private final StampedLock sl = new StampedLock();

  void move(double deltaX, double deltaY) { // an exclusively locked method
    long stamp = sl.writeLock();
    try {
      x = deltaX;
      y = deltaY;
    } finally {
      sl.unlockWrite(stamp);
    }
  }

  double distanceFromOrigin() { // A read-only method
    long stamp = sl.tryOptimisticRead();
    double currentX = x, currentY = y;
    if (!sl.validate(stamp)) {
       stamp = sl.readLock();
       try {
         currentX = x;
         currentY = y;
       } finally {
          sl.unlockRead(stamp);
       }
    }
    return Math.sqrt(currentX * currentX  currentY * currentY);
  }

  void moveIfAtOrigin(double newX, double newY) { // upgrade
    // Could instead start with optimistic, not read mode
    long stamp = sl.readLock();
    try {
      while (x == 0.0 && y == 0.0) {
        long ws = sl.tryConvertToWriteLock(stamp);
        if (ws != 0L) {
          stamp = ws;
          x = newX;
          y = newY;
          break;
        }
        else {
          sl.unlockRead(stamp);
          stamp = sl.writeLock();
        }
      }
    } finally {
      sl.unlock(stamp);
    }
  }
}
raw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close