mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8229442: AQS and lock classes refresh
Reviewed-by: martin
This commit is contained in:
parent
dbc8df3b97
commit
80fe274875
14 changed files with 1851 additions and 2778 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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™ Language Specification</cite></a>:
|
||||
* <cite>The Java™ 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
|
||||
|
|
|
@ -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");
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue