8187941: Add StampedLock stamp inspection methods
Reviewed-by: martin, psandoz
This commit is contained in:
parent
f8ae408aa9
commit
dc895e3911
src/java.base/share/classes/java/util/concurrent/locks
test/jdk/java/util/concurrent/tck
@ -140,7 +140,8 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* private double x, y;
|
||||
* private final StampedLock sl = new StampedLock();
|
||||
*
|
||||
* void move(double deltaX, double deltaY) { // an exclusively locked method
|
||||
* // an exclusively locked method
|
||||
* void move(double deltaX, double deltaY) {
|
||||
* long stamp = sl.writeLock();
|
||||
* try {
|
||||
* x += deltaX;
|
||||
@ -150,25 +151,57 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* double distanceFromOrigin() { // A read-only method
|
||||
* double currentX, currentY;
|
||||
* // a read-only method
|
||||
* // upgrade from optimistic read to read lock
|
||||
* double distanceFromOrigin() {
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* do {
|
||||
* if (stamp == 0L)
|
||||
* stamp = sl.readLock();
|
||||
* try {
|
||||
* try {
|
||||
* retryHoldingLock: for (;; stamp = sl.readLock()) {
|
||||
* if (stamp == 0L)
|
||||
* continue retryHoldingLock;
|
||||
* // possibly racy reads
|
||||
* currentX = x;
|
||||
* currentY = y;
|
||||
* } finally {
|
||||
* stamp = sl.tryConvertToOptimisticRead(stamp);
|
||||
* double currentX = x;
|
||||
* double currentY = y;
|
||||
* if (!sl.validate(stamp))
|
||||
* continue retryHoldingLock;
|
||||
* return Math.hypot(currentX, currentY);
|
||||
* }
|
||||
* } while (stamp == 0);
|
||||
* return Math.hypot(currentX, currentY);
|
||||
* } finally {
|
||||
* if (StampedLock.isReadLockStamp(stamp))
|
||||
* sl.unlockRead(stamp);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* void moveIfAtOrigin(double newX, double newY) { // upgrade
|
||||
* // Could instead start with optimistic, not read mode
|
||||
* // upgrade from optimistic read to write lock
|
||||
* void moveIfAtOrigin(double newX, double newY) {
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* try {
|
||||
* retryHoldingLock: for (;; stamp = sl.writeLock()) {
|
||||
* if (stamp == 0L)
|
||||
* continue retryHoldingLock;
|
||||
* // possibly racy reads
|
||||
* double currentX = x;
|
||||
* double currentY = y;
|
||||
* if (!sl.validate(stamp))
|
||||
* continue retryHoldingLock;
|
||||
* if (currentX != 0.0 || currentY != 0.0)
|
||||
* break;
|
||||
* stamp = sl.tryConvertToWriteLock(stamp);
|
||||
* if (stamp == 0L)
|
||||
* continue retryHoldingLock;
|
||||
* // exclusive access
|
||||
* x = newX;
|
||||
* y = newY;
|
||||
* return;
|
||||
* }
|
||||
* } finally {
|
||||
* if (StampedLock.isWriteLockStamp(stamp))
|
||||
* sl.unlockWrite(stamp);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Upgrade read lock to write lock
|
||||
* void moveIfAtOrigin(double newX, double newY) {
|
||||
* long stamp = sl.readLock();
|
||||
* try {
|
||||
* while (x == 0.0 && y == 0.0) {
|
||||
@ -881,6 +914,92 @@ public class StampedLock implements java.io.Serializable {
|
||||
return (state & RBITS) != 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a stamp represents holding a lock exclusively.
|
||||
* This method may be useful in conjunction with
|
||||
* {@link #tryConvertToWriteLock}, for example: <pre> {@code
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* try {
|
||||
* ...
|
||||
* stamp = sl.tryConvertToWriteLock(stamp);
|
||||
* ...
|
||||
* } finally {
|
||||
* if (StampedLock.isWriteLockStamp(stamp))
|
||||
* sl.unlockWrite(stamp);
|
||||
* }}</pre>
|
||||
*
|
||||
* @param stamp a stamp returned by a previous StampedLock operation
|
||||
* @return {@code true} if the stamp was returned by a successful
|
||||
* write-lock operation
|
||||
* @since 10
|
||||
*/
|
||||
public static boolean isWriteLockStamp(long stamp) {
|
||||
return (stamp & ABITS) == WBIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a stamp represents holding a lock non-exclusively.
|
||||
* This method may be useful in conjunction with
|
||||
* {@link #tryConvertToReadLock}, for example: <pre> {@code
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* try {
|
||||
* ...
|
||||
* stamp = sl.tryConvertToReadLock(stamp);
|
||||
* ...
|
||||
* } finally {
|
||||
* if (StampedLock.isReadLockStamp(stamp))
|
||||
* sl.unlockRead(stamp);
|
||||
* }}</pre>
|
||||
*
|
||||
* @param stamp a stamp returned by a previous StampedLock operation
|
||||
* @return {@code true} if the stamp was returned by a successful
|
||||
* read-lock operation
|
||||
* @since 10
|
||||
*/
|
||||
public static boolean isReadLockStamp(long stamp) {
|
||||
return (stamp & RBITS) != 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a stamp represents holding a lock.
|
||||
* This method may be useful in conjunction with
|
||||
* {@link #tryConvertToReadLock} and {@link #tryConvertToWriteLock},
|
||||
* for example: <pre> {@code
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* try {
|
||||
* ...
|
||||
* stamp = sl.tryConvertToReadLock(stamp);
|
||||
* ...
|
||||
* stamp = sl.tryConvertToWriteLock(stamp);
|
||||
* ...
|
||||
* } finally {
|
||||
* if (StampedLock.isLockStamp(stamp))
|
||||
* sl.unlock(stamp);
|
||||
* }}</pre>
|
||||
*
|
||||
* @param stamp a stamp returned by a previous StampedLock operation
|
||||
* @return {@code true} if the stamp was returned by a successful
|
||||
* read-lock or write-lock operation
|
||||
* @since 10
|
||||
*/
|
||||
public static boolean isLockStamp(long stamp) {
|
||||
return (stamp & ABITS) != 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a stamp represents a successful optimistic read.
|
||||
*
|
||||
* @param stamp a stamp returned by a previous StampedLock operation
|
||||
* @return {@code true} if the stamp was returned by a successful
|
||||
* optimistic read operation, that is, a non-zero return from
|
||||
* {@link #tryOptimisticRead()} or
|
||||
* {@link #tryConvertToOptimisticRead(long)}
|
||||
* @since 10
|
||||
*/
|
||||
public static boolean isOptimisticReadStamp(long stamp) {
|
||||
return (stamp & ABITS) == 0L && stamp != 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the number of read locks held for this lock. This
|
||||
* method is designed for use in monitoring system state, not for
|
||||
|
@ -35,6 +35,11 @@
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import static java.util.concurrent.locks.StampedLock.isLockStamp;
|
||||
import static java.util.concurrent.locks.StampedLock.isOptimisticReadStamp;
|
||||
import static java.util.concurrent.locks.StampedLock.isReadLockStamp;
|
||||
import static java.util.concurrent.locks.StampedLock.isWriteLockStamp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@ -1286,11 +1291,115 @@ public class StampedLockTest extends JSR166TestCase {
|
||||
} while (stamp == 0);
|
||||
return Math.hypot(currentX, currentY);
|
||||
}
|
||||
|
||||
double distanceFromOrigin2() {
|
||||
long stamp = sl.tryOptimisticRead();
|
||||
try {
|
||||
retryHoldingLock:
|
||||
for (;; stamp = sl.readLock()) {
|
||||
if (stamp == 0L)
|
||||
continue retryHoldingLock;
|
||||
// possibly racy reads
|
||||
double currentX = x;
|
||||
double currentY = y;
|
||||
if (!sl.validate(stamp))
|
||||
continue retryHoldingLock;
|
||||
return Math.hypot(currentX, currentY);
|
||||
}
|
||||
} finally {
|
||||
if (StampedLock.isReadLockStamp(stamp))
|
||||
sl.unlockRead(stamp);
|
||||
}
|
||||
}
|
||||
|
||||
void moveIfAtOrigin(double newX, double newY) {
|
||||
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;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
sl.unlockRead(stamp);
|
||||
stamp = sl.writeLock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sl.unlock(stamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Point p = new Point();
|
||||
p.move(3.0, 4.0);
|
||||
assertEquals(5.0, p.distanceFromOrigin());
|
||||
p.moveIfAtOrigin(5.0, 12.0);
|
||||
assertEquals(5.0, p.distanceFromOrigin2());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stamp inspection methods work as expected, and do not inspect
|
||||
* the state of the lock itself.
|
||||
*/
|
||||
public void testStampStateInspectionMethods() {
|
||||
StampedLock lock = new StampedLock();
|
||||
|
||||
assertFalse(isWriteLockStamp(0L));
|
||||
assertFalse(isReadLockStamp(0L));
|
||||
assertFalse(isLockStamp(0L));
|
||||
assertFalse(isOptimisticReadStamp(0L));
|
||||
|
||||
{
|
||||
long stamp = lock.writeLock();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
assertTrue(isWriteLockStamp(stamp));
|
||||
assertFalse(isReadLockStamp(stamp));
|
||||
assertTrue(isLockStamp(stamp));
|
||||
assertFalse(isOptimisticReadStamp(stamp));
|
||||
if (i == 0)
|
||||
lock.unlockWrite(stamp);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
long stamp = lock.readLock();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
assertFalse(isWriteLockStamp(stamp));
|
||||
assertTrue(isReadLockStamp(stamp));
|
||||
assertTrue(isLockStamp(stamp));
|
||||
assertFalse(isOptimisticReadStamp(stamp));
|
||||
if (i == 0)
|
||||
lock.unlockRead(stamp);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
long optimisticStamp = lock.tryOptimisticRead();
|
||||
long readStamp = lock.tryConvertToReadLock(optimisticStamp);
|
||||
long writeStamp = lock.tryConvertToWriteLock(readStamp);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
assertFalse(isWriteLockStamp(optimisticStamp));
|
||||
assertFalse(isReadLockStamp(optimisticStamp));
|
||||
assertFalse(isLockStamp(optimisticStamp));
|
||||
assertTrue(isOptimisticReadStamp(optimisticStamp));
|
||||
|
||||
assertFalse(isWriteLockStamp(readStamp));
|
||||
assertTrue(isReadLockStamp(readStamp));
|
||||
assertTrue(isLockStamp(readStamp));
|
||||
assertFalse(isOptimisticReadStamp(readStamp));
|
||||
|
||||
assertTrue(isWriteLockStamp(writeStamp));
|
||||
assertFalse(isReadLockStamp(writeStamp));
|
||||
assertTrue(isLockStamp(writeStamp));
|
||||
assertFalse(isOptimisticReadStamp(writeStamp));
|
||||
if (i == 0)
|
||||
lock.unlockWrite(writeStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user