com.github.benmanes.caffeine.cache.NonReentrantLock Maven / Gradle / Ivy
Show all versions of driver-cql-shaded Show documentation
/*
* Copyright 2014 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.benmanes.caffeine.cache;
import static java.util.Objects.requireNonNull;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* A non-reentrant mutual exclusion {@link Lock}. This type of lock does not allow recursive locks
* held by the same thread and will deadlock if used recursively. This type of lock is useful when
* reentrancy is not required and a slim lock is desired.
*
* A {@code NonReentrantLock} is owned by the thread last successfully locking, but not yet
* unlocking it. A thread invoking {@code lock} will return, successfully acquiring the lock, when
* the lock is not owned by another thread. This can be checked using methods
* {@link #isHeldByCurrentThread}.
*
* It is recommended practice to always immediately follow a call to {@code lock} with a
* {@code try} block, most typically in a before/after construction such as:
*
*
* {@code
* 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 {@link Lock} interface, this class defines a number of
* {@code public} and {@code 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.
*
* @author [email protected] (Ben Manes)
*/
final class NonReentrantLock implements Lock, Serializable {
static final long serialVersionUID = 1L;
/** Synchronizer providing all implementation mechanics */
final Sync sync;
public NonReentrantLock() {
this.sync = new Sync();
}
@Override
public void lock() {
sync.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.lockInterruptibly();
}
@Override
public boolean tryLock() {
return sync.tryLock();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryLock(time, unit);
}
@Override
public void unlock() {
sync.unlock();
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
/**
* Queries if this lock is held by the current thread.
*
* Analogous to the {@link Thread#holdsLock(Object)} method for built-in monitor locks, this
* method is typically used for debugging and testing. For example, a method that should only be
* called while a lock is held can assert that this is the case:
*
* {
* @code
* class X {
* ReentrantLock lock = new ReentrantLock();
*
* // ...
*
* public void m() {
* assert lock.isHeldByCurrentThread();
* // ... method body
* }
* }
* }
*
*
* It can also be used to ensure that a reentrant lock is used in a non-reentrant manner, for
* example:
*
*
* {
* @code
* class X {
* ReentrantLock lock = new ReentrantLock();
*
* // ...
*
* public void m() {
* assert !lock.isHeldByCurrentThread();
* lock.lock();
* try {
* // ... method body
* } finally {
* lock.unlock();
* }
* }
* }
* }
*
*
* @return {@code true} if current thread holds this lock and {@code false} otherwise
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* Queries if this lock is held by any thread. This method is designed for use in monitoring of
* the system state, not for synchronization control.
*
* @return {@code true} if any thread holds this lock and {@code false} otherwise
*/
public boolean isLocked() {
return sync.isLocked();
}
/**
* Returns the thread that currently owns this lock, or {@code null} if not owned. When this
* method is called by a thread that is not the owner, the return value reflects a best-effort
* approximation of current lock status. For example, the owner may be momentarily {@code null}
* even if there are threads trying to acquire the lock but have not yet done so. This method is
* designed to facilitate construction of subclasses that provide more extensive lock monitoring
* facilities.
*
* @return the owner, or {@code null} if not owned
*/
public Thread getOwner() {
return sync.getOwner();
}
/**
* Queries whether any threads are waiting to acquire this lock. Note that because cancellations
* may occur at any time, a {@code true} return does not guarantee that any other thread will ever
* acquire this lock. This method is designed primarily for use in monitoring of the system state.
*
* @return {@code true} if there may be other threads waiting to acquire the lock
*/
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* Queries whether the given thread is waiting to acquire this lock. Note that because
* cancellations may occur at any time, a {@code true} return does not guarantee that this thread
* will ever acquire this lock. This method is designed primarily for use in monitoring of the
* system state.
*
* @param thread the thread
* @return {@code true} if the given thread is queued waiting for this lock
* @throws NullPointerException if the thread is null
*/
public boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* Returns an estimate of the number of threads waiting to acquire this lock. The value is only an
* estimate because the number of threads may change dynamically while this method traverses
* internal data structures. This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return the estimated number of threads waiting for this lock
*/
public int getQueueLength() {
return sync.getQueueLength();
}
/**
* Returns a collection containing threads that may be waiting to acquire this lock. Because the
* actual set of threads may change dynamically while constructing this result, the returned
* collection is only a best-effort estimate. The elements of the returned collection are in no
* particular order. This method is designed to facilitate construction of subclasses that provide
* more extensive monitoring facilities.
*
* @return the collection of threads
*/
public Collection getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* Queries whether any threads are waiting on the given condition associated with this lock. Note
* that because timeouts and interrupts may occur at any time, a {@code true} return does not
* guarantee that a future {@code signal} will awaken any threads. This method is designed
* primarily for use in monitoring of the system state.
*
* @param condition the condition
* @return {@code true} if there are any waiting threads
* @throws IllegalMonitorStateException if this lock is not held
* @throws IllegalArgumentException if the given condition is not associated with this lock
* @throws NullPointerException if the condition is null
*/
public boolean hasWaiters(Condition condition) {
requireNonNull(condition);
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) {
throw new IllegalArgumentException("not owner");
}
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject) condition);
}
/**
* Returns an estimate of the number of threads waiting on the given condition associated with
* this lock. Note that because timeouts and interrupts may occur at any time, the estimate serves
* only as an upper bound on the actual number of waiters. This method is designed for use in
* monitoring of the system state, not for synchronization control.
*
* @param condition the condition
* @return the estimated number of waiting threads
* @throws IllegalMonitorStateException if this lock is not held
* @throws IllegalArgumentException if the given condition is not associated with this lock
* @throws NullPointerException if the condition is null
*/
public int getWaitQueueLength(Condition condition) {
requireNonNull(condition);
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) {
throw new IllegalArgumentException("not owner");
}
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject) condition);
}
/**
* Returns a collection containing those threads that may be waiting on the given condition
* associated with this lock. Because the actual set of threads may change dynamically while
* constructing this result, the returned collection is only a best-effort estimate. The elements
* of the returned collection are in no particular order. This method is designed to facilitate
* construction of subclasses that provide more extensive condition monitoring facilities.
*
* @param condition the condition
* @return the collection of threads
* @throws IllegalMonitorStateException if this lock is not held
* @throws IllegalArgumentException if the given condition is not associated with this lock
* @throws NullPointerException if the condition is null
*/
public Collection getWaitingThreads(Condition condition) {
requireNonNull(condition);
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) {
throw new IllegalArgumentException("not owner");
}
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject) condition);
}
/**
* Returns a string identifying this lock, as well as its lock state. The state, in brackets,
* includes either the String {@code "Unlocked"} or the String {@code "Locked by"} followed by the
* {@linkplain Thread#getName name} of the owning thread.
*
* @return a string identifying this lock, as well as its lock state
*/
@Override
public String toString() {
Thread o = sync.getOwner();
String status = (o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]";
return super.toString() + status;
}
/** A non-fair lock using AQS state to represent if the lock is held. */
static final class Sync extends AbstractQueuedSynchronizer implements Lock, Serializable {
static final long serialVersionUID = 1L;
static final int UNLOCKED = 0;
static final int LOCKED = 1;
@Override
public void lock() {
acquire(LOCKED);
}
@Override
public void lockInterruptibly() throws InterruptedException {
acquireInterruptibly(LOCKED);
}
@Override
public boolean tryLock() {
return tryAcquire(LOCKED);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
release(UNLOCKED);
}
@Override
public Condition newCondition() {
return new ConditionObject();
}
@Override
protected boolean tryAcquire(int acquires) {
if ((getState() == UNLOCKED) && compareAndSetState(UNLOCKED, LOCKED)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int releases) {
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(UNLOCKED);
return true;
}
@Override
protected boolean isHeldExclusively() {
return isLocked() && (getExclusiveOwnerThread() == Thread.currentThread());
}
public boolean isLocked() {
return getState() == LOCKED;
}
public Thread getOwner() {
return getExclusiveOwnerThread();
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(UNLOCKED);
}
}
}