8229442: AQS and lock classes refresh

Reviewed-by: martin
This commit is contained in:
Doug Lea 2019-09-14 11:16:40 -07:00
parent dbc8df3b97
commit 80fe274875
14 changed files with 1851 additions and 2778 deletions

View file

@ -122,9 +122,8 @@ import java.util.concurrent.TimeUnit;
* <p>All {@code Lock} implementations <em>must</em> enforce the same
* memory synchronization semantics as provided by the built-in monitor
* lock, as described in
* <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
* Chapter 17 of
* <cite>The Java&trade; Language Specification</cite></a>:
* <cite>The Java&trade; Language Specification</cite>:
* <ul>
* <li>A successful {@code lock} operation has the same memory
* synchronization effects as a successful <em>Lock</em> action.
@ -162,6 +161,7 @@ import java.util.concurrent.TimeUnit;
* @see ReentrantLock
* @see Condition
* @see ReadWriteLock
* @jls 17.4 Memory Model
*
* @since 1.5
* @author Doug Lea

View file

@ -140,8 +140,25 @@ public class LockSupport {
private LockSupport() {} // Cannot be instantiated.
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
U.putReference(t, PARKBLOCKER, arg);
U.putReferenceOpaque(t, PARKBLOCKER, arg);
}
/**
* Sets the object to be returned by invocations of {@link
* #getBlocker getBlocker} for the current thread. This method may
* be used before invoking the no-argument version of {@link
* LockSupport#park() park()} from non-public objects, allowing
* more helpful diagnostics, or retaining compatibility with
* previous implementations of blocking methods. Previous values
* of the blocker are not automatically restored after blocking.
* To obtain the effects of {@code park(b}}, use {@code
* setCurrentBlocker(b); park(); setCurrentBlocker(null);}
*
* @param blocker the blocker object
* @since 14
*/
public static void setCurrentBlocker(Object blocker) {
U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
}
/**
@ -292,7 +309,7 @@ public class LockSupport {
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return U.getReferenceVolatile(t, PARKBLOCKER);
return U.getReferenceOpaque(t, PARKBLOCKER);
}
/**
@ -393,24 +410,6 @@ public class LockSupport {
U.park(true, deadline);
}
/**
* Returns the pseudo-randomly initialized or updated secondary seed.
* Copied from ThreadLocalRandom due to package access restrictions.
*/
static final int nextSecondarySeed() {
int r;
Thread t = Thread.currentThread();
if ((r = U.getInt(t, SECONDARY)) != 0) {
r ^= r << 13; // xorshift
r ^= r >>> 17;
r ^= r << 5;
}
else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
r = 1; // avoid zero
U.putInt(t, SECONDARY, r);
return r;
}
/**
* Returns the thread id for the given thread. We must access
* this directly rather than via method Thread.getId() because
@ -423,11 +422,9 @@ public class LockSupport {
// Hotspot implementation via intrinsics API
private static final Unsafe U = Unsafe.getUnsafe();
private static final long PARKBLOCKER = U.objectFieldOffset
(Thread.class, "parkBlocker");
private static final long SECONDARY = U.objectFieldOffset
(Thread.class, "threadLocalRandomSecondarySeed");
private static final long TID = U.objectFieldOffset
(Thread.class, "tid");
private static final long PARKBLOCKER
= U.objectFieldOffset(Thread.class, "parkBlocker");
private static final long TID
= U.objectFieldOffset(Thread.class, "tid");
}

View file

@ -119,39 +119,63 @@ public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
* Performs non-fair tryLock.
*/
@ReservedStackAccess
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
final boolean tryLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
setState(c);
return true;
}
return false;
}
/**
* Checks for reentrancy and acquires if lock immediately
* available under fair vs nonfair rules. Locking methods
* perform initialTryLock check before relaying to
* corresponding AQS acquire methods.
*/
abstract boolean initialTryLock();
@ReservedStackAccess
final void lock() {
if (!initialTryLock())
acquire(1);
}
@ReservedStackAccess
final void lockInterruptibly() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!initialTryLock())
acquireInterruptibly(1);
}
@ReservedStackAccess
final boolean tryLockNanos(long nanos) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return initialTryLock() || tryAcquireNanos(1, nanos);
}
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
boolean free = (c == 0);
if (free)
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
@ -195,8 +219,31 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final boolean initialTryLock() {
Thread current = Thread.currentThread();
if (compareAndSetState(0, 1)) { // first attempt is unguarded
setExclusiveOwnerThread(current);
return true;
} else if (getExclusiveOwnerThread() == current) {
int c = getState() + 1;
if (c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
} else
return false;
}
/**
* Acquire for non-reentrant cases after initialTryLock prescreen
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
if (getState() == 0 && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}
@ -205,26 +252,34 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
* Acquires only if reentrant or queue is empty.
*/
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
final boolean initialTryLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
setState(c);
return true;
}
return false;
}
/**
* Acquires only if thread is first waiter or empty
*/
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && !hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
@ -264,7 +319,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
* at which time the lock hold count is set to one.
*/
public void lock() {
sync.acquire(1);
sync.lock();
}
/**
@ -314,7 +369,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
* @throws InterruptedException if the current thread is interrupted
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
sync.lockInterruptibly();
}
/**
@ -344,7 +399,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
* thread; and {@code false} otherwise
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
return sync.tryLock();
}
/**
@ -421,7 +476,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
return sync.tryLockNanos(unit.toNanos(timeout));
}
/**