src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Tue Oct 03 13:32:04 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Tue Oct 03 13:37:01 2017 -0700
@@ -194,19 +194,13 @@
* 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:
+ * It also supports conditions and exposes some instrumentation methods:
*
* <pre> {@code
* 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
@@ -220,14 +214,27 @@
* // Releases the lock by setting state to zero
* protected boolean tryRelease(int releases) {
* assert releases == 1; // Otherwise unused
- * if (getState() == 0) throw new IllegalMonitorStateException();
+ * if (!isHeldExclusively())
+ * throw new IllegalMonitorStateException();
* setExclusiveOwnerThread(null);
* setState(0);
* return true;
* }
*
+ * // Reports whether in locked state
+ * public boolean isLocked() {
+ * return getState() != 0;
+ * }
+ *
+ * public boolean isHeldExclusively() {
+ * // a data race, but safe due to out-of-thin-air guarantees
+ * return getExclusiveOwnerThread() == Thread.currentThread();
+ * }
+ *
* // Provides a Condition
- * Condition newCondition() { return new ConditionObject(); }
+ * public Condition newCondition() {
+ * return new ConditionObject();
+ * }
*
* // Deserializes properly
* private void readObject(ObjectInputStream s)
@@ -240,12 +247,17 @@
* // 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 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.isLocked(); }
+ * public boolean isHeldByCurrentThread() {
+ * return sync.isHeldExclusively();
+ * }
+ * public boolean hasQueuedThreads() {
+ * return sync.hasQueuedThreads();
+ * }
* public void lockInterruptibly() throws InterruptedException {
* sync.acquireInterruptibly(1);
* }
@@ -1193,8 +1205,7 @@
/**
* Returns {@code true} if synchronization is held exclusively with
* respect to the current (calling) thread. This method is invoked
- * upon each call to a non-waiting {@link ConditionObject} method.
- * (Waiting methods instead invoke {@link #release}.)
+ * upon each call to a {@link ConditionObject} method.
*
* <p>The default implementation throws {@link
* UnsupportedOperationException}. This method is invoked
@@ -1834,9 +1845,8 @@
}
/**
- * Condition implementation for a {@link
- * AbstractQueuedSynchronizer} serving as the basis of a {@link
- * Lock} implementation.
+ * Condition implementation for a {@link AbstractQueuedSynchronizer}
+ * serving as the basis of a {@link Lock} implementation.
*
* <p>Method documentation for this class describes mechanics,
* not behavioral specifications from the point of view of Lock
@@ -1867,6 +1877,8 @@
* @return its new wait node
*/
private Node addConditionWaiter() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {