diff --git a/jdk/src/java.base/share/classes/java/util/Queue.java b/jdk/src/java.base/share/classes/java/util/Queue.java
index 7d5e39c7030..e94b22c7fb2 100644
--- a/jdk/src/java.base/share/classes/java/util/Queue.java
+++ b/jdk/src/java.base/share/classes/java/util/Queue.java
@@ -124,7 +124,6 @@ package java.util;
* always well-defined for queues with the same elements but different
* ordering properties.
*
- *
*
This interface is a member of the
*
* Java Collections Framework .
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
index d2392c62798..471316a9040 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
@@ -68,6 +68,7 @@ import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;
+import jdk.internal.misc.Unsafe;
/**
* A hash table supporting full concurrency of retrievals and
@@ -747,7 +748,7 @@ public class ConcurrentHashMap extends AbstractMap
/* ---------------- Table element access -------------- */
/*
- * Volatile access methods are used for table elements as well as
+ * Atomic access methods are used for table elements as well as
* elements of in-progress next table while resizing. All uses of
* the tab arguments must be null checked by callers. All callers
* also paranoically precheck that tab's length is not zero (or an
@@ -757,14 +758,12 @@ public class ConcurrentHashMap extends AbstractMap
* errors by users, these checks must operate on local variables,
* which accounts for some odd-looking inline assignments below.
* Note that calls to setTabAt always occur within locked regions,
- * and so in principle require only release ordering, not
- * full volatile semantics, but are currently coded as volatile
- * writes to be conservative.
+ * and so require only release ordering.
*/
@SuppressWarnings("unchecked")
static final Node tabAt(Node[] tab, int i) {
- return (Node)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+ return (Node)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}
static final boolean casTabAt(Node[] tab, int i,
@@ -773,7 +772,7 @@ public class ConcurrentHashMap extends AbstractMap
}
static final void setTabAt(Node[] tab, int i, Node v) {
- U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+ U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
}
/* ---------------- Fields -------------- */
@@ -3298,7 +3297,7 @@ public class ConcurrentHashMap extends AbstractMap
return true;
}
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private static final long LOCKSTATE;
static {
try {
@@ -6341,7 +6340,7 @@ public class ConcurrentHashMap extends AbstractMap
}
// Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java
index 698079066cb..e8193a00256 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
@@ -292,64 +294,23 @@ public class ConcurrentLinkedDeque
volatile Node prev;
volatile E item;
volatile Node next;
+ }
- Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
- }
-
- /**
- * Constructs a new node. Uses relaxed write because item can
- * only be seen after publication via casNext or casPrev.
- */
- Node(E item) {
- U.putObject(this, ITEM, item);
- }
-
- boolean casItem(E cmp, E val) {
- return U.compareAndSwapObject(this, ITEM, cmp, val);
- }
-
- void lazySetNext(Node val) {
- U.putObjectRelease(this, NEXT, val);
- }
-
- boolean casNext(Node cmp, Node val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
- }
-
- void lazySetPrev(Node val) {
- U.putObjectRelease(this, PREV, val);
- }
-
- boolean casPrev(Node cmp, Node val) {
- return U.compareAndSwapObject(this, PREV, cmp, val);
- }
-
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long PREV;
- private static final long ITEM;
- private static final long NEXT;
-
- static {
- try {
- PREV = U.objectFieldOffset
- (Node.class.getDeclaredField("prev"));
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
+ /**
+ * Returns a new node holding item. Uses relaxed write because item
+ * can only be seen after piggy-backing publication via CAS.
+ */
+ static Node newNode(E item) {
+ Node node = new Node();
+ ITEM.set(node, item);
+ return node;
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
- final Node newNode = new Node(Objects.requireNonNull(e));
+ final Node newNode = newNode(Objects.requireNonNull(e));
restartFromHead:
for (;;)
@@ -363,13 +324,13 @@ public class ConcurrentLinkedDeque
continue restartFromHead;
else {
// p is first node
- newNode.lazySetNext(p); // CAS piggyback
- if (p.casPrev(null, newNode)) {
+ NEXT.set(newNode, p); // CAS piggyback
+ if (PREV.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
- if (p != h) // hop two nodes at a time
- casHead(h, newNode); // Failure is OK.
+ if (p != h) // hop two nodes at a time; failure is OK
+ HEAD.weakCompareAndSetVolatile(this, h, newNode);
return;
}
// Lost CAS race to another thread; re-read prev
@@ -381,7 +342,7 @@ public class ConcurrentLinkedDeque
* Links e as last element.
*/
private void linkLast(E e) {
- final Node newNode = new Node(Objects.requireNonNull(e));
+ final Node newNode = newNode(Objects.requireNonNull(e));
restartFromTail:
for (;;)
@@ -395,13 +356,13 @@ public class ConcurrentLinkedDeque
continue restartFromTail;
else {
// p is last node
- newNode.lazySetPrev(p); // CAS piggyback
- if (p.casNext(null, newNode)) {
+ PREV.set(newNode, p); // CAS piggyback
+ if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
- if (p != t) // hop two nodes at a time
- casTail(t, newNode); // Failure is OK.
+ if (p != t) // hop two nodes at a time; failure is OK
+ TAIL.weakCompareAndSetVolatile(this, t, newNode);
return;
}
// Lost CAS race to another thread; re-read next
@@ -516,8 +477,8 @@ public class ConcurrentLinkedDeque
updateTail(); // Ensure x is not reachable from tail
// Finally, actually gc-unlink
- x.lazySetPrev(isFirst ? prevTerminator() : x);
- x.lazySetNext(isLast ? nextTerminator() : x);
+ PREV.setRelease(x, isFirst ? prevTerminator() : x);
+ NEXT.setRelease(x, isLast ? nextTerminator() : x);
}
}
}
@@ -531,7 +492,8 @@ public class ConcurrentLinkedDeque
// assert first.item == null;
for (Node o = null, p = next, q;;) {
if (p.item != null || (q = p.next) == null) {
- if (o != null && p.prev != p && first.casNext(next, p)) {
+ if (o != null && p.prev != p &&
+ NEXT.compareAndSet(first, next, p)) {
skipDeletedPredecessors(p);
if (first.prev == null &&
(p.next == null || p.item != null) &&
@@ -541,8 +503,8 @@ public class ConcurrentLinkedDeque
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
- o.lazySetNext(o);
- o.lazySetPrev(prevTerminator());
+ NEXT.setRelease(o, o);
+ PREV.setRelease(o, prevTerminator());
}
}
return;
@@ -565,7 +527,8 @@ public class ConcurrentLinkedDeque
// assert last.item == null;
for (Node o = null, p = prev, q;;) {
if (p.item != null || (q = p.prev) == null) {
- if (o != null && p.next != p && last.casPrev(prev, p)) {
+ if (o != null && p.next != p &&
+ PREV.compareAndSet(last, prev, p)) {
skipDeletedSuccessors(p);
if (last.next == null &&
(p.prev == null || p.item != null) &&
@@ -575,8 +538,8 @@ public class ConcurrentLinkedDeque
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
- o.lazySetPrev(o);
- o.lazySetNext(nextTerminator());
+ PREV.setRelease(o, o);
+ NEXT.setRelease(o, nextTerminator());
}
}
return;
@@ -607,7 +570,7 @@ public class ConcurrentLinkedDeque
(q = (p = q).prev) == null) {
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- if (casHead(h, p))
+ if (HEAD.compareAndSet(this, h, p))
return;
else
continue restartFromHead;
@@ -637,7 +600,7 @@ public class ConcurrentLinkedDeque
(q = (p = q).next) == null) {
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- if (casTail(t, p))
+ if (TAIL.compareAndSet(this, t, p))
return;
else
continue restartFromTail;
@@ -675,7 +638,7 @@ public class ConcurrentLinkedDeque
}
// found active CAS target
- if (prev == p || x.casPrev(prev, p))
+ if (prev == p || PREV.compareAndSet(x, prev, p))
return;
} while (x.item != null || x.next == null);
@@ -706,7 +669,7 @@ public class ConcurrentLinkedDeque
}
// found active CAS target
- if (next == p || x.casNext(next, p))
+ if (next == p || NEXT.compareAndSet(x, next, p))
return;
} while (x.item != null || x.prev == null);
@@ -751,7 +714,7 @@ public class ConcurrentLinkedDeque
else if (p == h
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- || casHead(h, p))
+ || HEAD.compareAndSet(this, h, p))
return p;
else
continue restartFromHead;
@@ -776,7 +739,7 @@ public class ConcurrentLinkedDeque
else if (p == t
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
- || casTail(t, p))
+ || TAIL.compareAndSet(this, t, p))
return p;
else
continue restartFromTail;
@@ -802,7 +765,7 @@ public class ConcurrentLinkedDeque
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
- head = tail = new Node(null);
+ head = tail = new Node();
}
/**
@@ -818,12 +781,12 @@ public class ConcurrentLinkedDeque
// Copy c into a private chain of Nodes
Node h = null, t = null;
for (E e : c) {
- Node newNode = new Node(Objects.requireNonNull(e));
+ Node newNode = newNode(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
@@ -836,12 +799,12 @@ public class ConcurrentLinkedDeque
private void initHeadTail(Node h, Node t) {
if (h == t) {
if (h == null)
- h = t = new Node(null);
+ h = t = new Node();
else {
// Avoid edge case of a single Node with non-null item.
- Node newNode = new Node(null);
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ Node newNode = new Node();
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
@@ -934,7 +897,7 @@ public class ConcurrentLinkedDeque
public E pollFirst() {
for (Node p = first(); p != null; p = succ(p)) {
E item = p.item;
- if (item != null && p.casItem(item, null)) {
+ if (item != null && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return item;
}
@@ -945,7 +908,7 @@ public class ConcurrentLinkedDeque
public E pollLast() {
for (Node p = last(); p != null; p = pred(p)) {
E item = p.item;
- if (item != null && p.casItem(item, null)) {
+ if (item != null && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return item;
}
@@ -1031,7 +994,8 @@ public class ConcurrentLinkedDeque
Objects.requireNonNull(o);
for (Node p = first(); p != null; p = succ(p)) {
E item = p.item;
- if (item != null && o.equals(item) && p.casItem(item, null)) {
+ if (item != null && o.equals(item) &&
+ ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@@ -1055,7 +1019,8 @@ public class ConcurrentLinkedDeque
Objects.requireNonNull(o);
for (Node p = last(); p != null; p = pred(p)) {
E item = p.item;
- if (item != null && o.equals(item) && p.casItem(item, null)) {
+ if (item != null && o.equals(item) &&
+ ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@@ -1159,12 +1124,12 @@ public class ConcurrentLinkedDeque
// Copy c into a private chain of Nodes
Node beginningOfTheEnd = null, last = null;
for (E e : c) {
- Node newNode = new Node(Objects.requireNonNull(e));
+ Node newNode = newNode(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- last.lazySetNext(newNode);
- newNode.lazySetPrev(last);
+ NEXT.set(last, newNode);
+ PREV.set(newNode, last);
last = newNode;
}
}
@@ -1184,16 +1149,16 @@ public class ConcurrentLinkedDeque
continue restartFromTail;
else {
// p is last node
- beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
- if (p.casNext(null, beginningOfTheEnd)) {
+ PREV.set(beginningOfTheEnd, p); // CAS piggyback
+ if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this deque.
- if (!casTail(t, last)) {
+ if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
- casTail(t, last);
+ TAIL.weakCompareAndSetVolatile(this, t, last);
}
return true;
}
@@ -1586,41 +1551,38 @@ public class ConcurrentLinkedDeque
Node h = null, t = null;
for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
- Node newNode = new Node((E) item);
+ Node newNode = newNode((E) item);
if (h == null)
h = t = newNode;
else {
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
initHeadTail(h, t);
}
- private boolean casHead(Node cmp, Node val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
- }
-
- private boolean casTail(Node cmp, Node val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
- }
-
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ private static final VarHandle PREV;
+ private static final VarHandle NEXT;
+ private static final VarHandle ITEM;
static {
PREV_TERMINATOR = new Node();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node();
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
try {
- HEAD = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
+ Node.class);
+ PREV = l.findVarHandle(Node.class, "prev", Node.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java
index ae246a4e780..1e3f1aad4f6 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@@ -166,9 +168,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue
* this is merely an optimization.
*
* When constructing a Node (before enqueuing it) we avoid paying
- * for a volatile write to item by using Unsafe.putObject instead
- * of a normal write. This allows the cost of enqueue to be
- * "one-and-a-half" CASes.
+ * for a volatile write to item. This allows the cost of enqueue
+ * to be "one-and-a-half" CASes.
*
* Both head and tail may or may not point to a Node with a
* non-null item. If the queue is empty, all items must of course
@@ -178,33 +179,21 @@ public class ConcurrentLinkedQueue extends AbstractQueue
* optimization.
*/
- private static class Node {
+ static final class Node {
volatile E item;
volatile Node next;
}
/**
* Returns a new node holding item. Uses relaxed write because item
- * can only be seen after piggy-backing publication via casNext.
+ * can only be seen after piggy-backing publication via CAS.
*/
static Node newNode(E item) {
Node node = new Node();
- U.putObject(node, ITEM, item);
+ ITEM.set(node, item);
return node;
}
- static boolean casItem(Node node, E cmp, E val) {
- return U.compareAndSwapObject(node, ITEM, cmp, val);
- }
-
- static void lazySetNext(Node node, Node val) {
- U.putObjectRelease(node, NEXT, val);
- }
-
- static boolean casNext(Node node, Node cmp, Node val) {
- return U.compareAndSwapObject(node, NEXT, cmp, val);
- }
-
/**
* A node from which the first live (non-deleted) node (if any)
* can be reached in O(1) time.
@@ -256,7 +245,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue
if (h == null)
h = t = newNode;
else {
- lazySetNext(t, newNode);
+ NEXT.set(t, newNode);
t = newNode;
}
}
@@ -286,8 +275,8 @@ public class ConcurrentLinkedQueue extends AbstractQueue
*/
final void updateHead(Node h, Node p) {
// assert h != null && p != null && (h == p || h.item == null);
- if (h != p && casHead(h, p))
- lazySetNext(h, h);
+ if (h != p && HEAD.compareAndSet(this, h, p))
+ NEXT.setRelease(h, h);
}
/**
@@ -314,12 +303,12 @@ public class ConcurrentLinkedQueue extends AbstractQueue
Node q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, newNode)) {
+ if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
- if (p != t) // hop two nodes at a time
- casTail(t, newNode); // Failure is OK.
+ if (p != t) // hop two nodes at a time; failure is OK
+ TAIL.weakCompareAndSetVolatile(this, t, newNode);
return true;
}
// Lost CAS race to another thread; re-read next
@@ -342,7 +331,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue
for (Node h = head, p = h, q;;) {
E item = p.item;
- if (item != null && casItem(p, item, null)) {
+ if (item != null && ITEM.compareAndSet(p, item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
if (p != h) // hop two nodes at a time
@@ -483,12 +472,12 @@ public class ConcurrentLinkedQueue extends AbstractQueue
next = succ(p);
continue;
}
- removed = casItem(p, item, null);
+ removed = ITEM.compareAndSet(p, item, null);
}
next = succ(p);
if (pred != null && next != null) // unlink
- casNext(pred, p, next);
+ NEXT.weakCompareAndSetVolatile(pred, p, next);
if (removed)
return true;
}
@@ -520,7 +509,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- lazySetNext(last, newNode);
+ NEXT.set(last, newNode);
last = newNode;
}
}
@@ -532,15 +521,15 @@ public class ConcurrentLinkedQueue extends AbstractQueue
Node q = p.next;
if (q == null) {
// p is last node
- if (casNext(p, null, beginningOfTheEnd)) {
+ if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this queue.
- if (!casTail(t, last)) {
+ if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
- casTail(t, last);
+ TAIL.weakCompareAndSetVolatile(this, t, last);
}
return true;
}
@@ -744,7 +733,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue
}
// unlink deleted nodes
if ((q = succ(p)) != null)
- casNext(pred, p, q);
+ NEXT.compareAndSet(pred, p, q);
}
}
@@ -801,7 +790,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue
if (h == null)
h = t = newNode;
else {
- lazySetNext(t, newNode);
+ NEXT.set(t, newNode);
t = newNode;
}
}
@@ -919,31 +908,20 @@ public class ConcurrentLinkedQueue extends AbstractQueue
return new CLQSpliterator(this);
}
- private boolean casTail(Node cmp, Node val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
- }
-
- private boolean casHead(Node cmp, Node val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
- }
-
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
- private static final long ITEM;
- private static final long NEXT;
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ private static final VarHandle ITEM;
+ private static final VarHandle NEXT;
static {
try {
- HEAD = U.objectFieldOffset
- (ConcurrentLinkedQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
+ Node.class);
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
index fa53ded9710..7734a265bed 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
@@ -401,7 +403,7 @@ public class ConcurrentSkipListMap extends AbstractMap
* compareAndSet head node.
*/
private boolean casHead(HeadIndex cmp, HeadIndex val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return HEAD.compareAndSet(this, cmp, val);
}
/* ---------------- Nodes -------------- */
@@ -444,14 +446,14 @@ public class ConcurrentSkipListMap extends AbstractMap
* compareAndSet value field.
*/
boolean casValue(Object cmp, Object val) {
- return U.compareAndSwapObject(this, VALUE, cmp, val);
+ return VALUE.compareAndSet(this, cmp, val);
}
/**
* compareAndSet next field.
*/
boolean casNext(Node cmp, Node val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return NEXT.compareAndSet(this, cmp, val);
}
/**
@@ -532,20 +534,16 @@ public class ConcurrentSkipListMap extends AbstractMap
return new AbstractMap.SimpleImmutableEntry(key, vv);
}
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
- private static final long NEXT;
-
+ // VarHandle mechanics
+ private static final VarHandle VALUE;
+ private static final VarHandle NEXT;
static {
try {
- VALUE = U.objectFieldOffset
- (Node.class.getDeclaredField("value"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(Node.class, "value", Object.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new Error(e);
}
}
}
@@ -577,7 +575,7 @@ public class ConcurrentSkipListMap extends AbstractMap
* compareAndSet right field.
*/
final boolean casRight(Index cmp, Index val) {
- return U.compareAndSwapObject(this, RIGHT, cmp, val);
+ return RIGHT.compareAndSet(this, cmp, val);
}
/**
@@ -613,13 +611,12 @@ public class ConcurrentSkipListMap extends AbstractMap
return node.value != null && casRight(succ, succ.right);
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long RIGHT;
+ // VarHandle mechanics
+ private static final VarHandle RIGHT;
static {
try {
- RIGHT = U.objectFieldOffset
- (Index.class.getDeclaredField("right"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -3607,13 +3604,13 @@ public class ConcurrentSkipListMap extends AbstractMap
}
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
static {
try {
- HEAD = U.objectFieldOffset
- (ConcurrentSkipListMap.class.getDeclaredField("head"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
+ HeadIndex.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java
index 2ecacf8e185..45bde4215c5 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
@@ -507,15 +509,16 @@ public class ConcurrentSkipListSet
// Support for resetting map in clone
private void setMap(ConcurrentNavigableMap map) {
- U.putObjectVolatile(this, MAP, map);
+ MAP.setVolatile(this, map);
}
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long MAP;
+ // VarHandle mechanics
+ private static final VarHandle MAP;
static {
try {
- MAP = U.objectFieldOffset
- (ConcurrentSkipListSet.class.getDeclaredField("m"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ MAP = l.findVarHandle(ConcurrentSkipListSet.class, "m",
+ ConcurrentNavigableMap.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
index 65baf7c87c8..1f1b83cbfca 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
@@ -34,6 +34,7 @@
package java.util.concurrent;
+import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
@@ -1541,17 +1542,21 @@ public class CopyOnWriteArrayList
}
}
- // Support for resetting lock while deserializing
+ /** Initializes the lock; for use when deserializing or cloning. */
private void resetLock() {
- U.putObjectVolatile(this, LOCK, new Object());
- }
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long LOCK;
- static {
+ Field lockField = java.security.AccessController.doPrivileged(
+ (java.security.PrivilegedAction) () -> {
+ try {
+ Field f = CopyOnWriteArrayList.class
+ .getDeclaredField("lock");
+ f.setAccessible(true);
+ return f;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }});
try {
- LOCK = U.objectFieldOffset
- (CopyOnWriteArrayList.class.getDeclaredField("lock"));
- } catch (ReflectiveOperationException e) {
+ lockField.set(this, new Object());
+ } catch (IllegalAccessException e) {
throw new Error(e);
}
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java b/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java
index 1e56b09dfc1..a61762b5669 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java
@@ -35,6 +35,9 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* A {@link ForkJoinTask} with a completion action performed when
* triggered and there are no remaining pending actions.
@@ -524,7 +527,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
- U.getAndAddInt(this, PENDING, delta);
+ PENDING.getAndAdd(this, delta);
}
/**
@@ -536,7 +539,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
* @return {@code true} if successful
*/
public final boolean compareAndSetPendingCount(int expected, int count) {
- return U.compareAndSwapInt(this, PENDING, expected, count);
+ return PENDING.compareAndSet(this, expected, count);
}
/**
@@ -548,7 +551,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
public final int decrementPendingCountUnlessZero() {
int c;
do {} while ((c = pending) != 0 &&
- !U.compareAndSwapInt(this, PENDING, c, c - 1));
+ !PENDING.weakCompareAndSetVolatile(this, c, c - 1));
return c;
}
@@ -581,7 +584,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@@ -604,7 +607,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@@ -649,7 +652,7 @@ public abstract class CountedCompleter extends ForkJoinTask {
for (int c;;) {
if ((c = pending) == 0)
return this;
- else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSetVolatile(this, c, c - 1))
return null;
}
}
@@ -753,13 +756,13 @@ public abstract class CountedCompleter extends ForkJoinTask {
*/
protected void setRawResult(T t) { }
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long PENDING;
+ // VarHandle mechanics
+ private static final VarHandle PENDING;
static {
try {
- PENDING = U.objectFieldOffset
- (CountedCompleter.class.getDeclaredField("pending"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
+
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java
index 069d6e0f871..8dcfe9bf1df 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java
@@ -36,6 +36,10 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.locks.LockSupport;
+
/**
* A synchronization point at which threads can pair and swap elements
* within pairs. Each thread presents some object on entry to the
@@ -155,9 +159,7 @@ public class Exchanger {
* a value that is enough for common platforms. Additionally,
* extra care elsewhere is taken to avoid other false/unintended
* sharing and to enhance locality, including adding padding (via
- * @Contended) to Nodes, embedding "bound" as an Exchanger field,
- * and reworking some park/unpark mechanics compared to
- * LockSupport versions.
+ * @Contended) to Nodes, embedding "bound" as an Exchanger field.
*
* The arena starts out with only one used slot. We expand the
* effective arena size by tracking collisions; i.e., failed CASes
@@ -234,12 +236,12 @@ public class Exchanger {
* because most of the logic relies on reads of fields that are
* maintained as local variables so can't be nicely factored --
* mainly, here, bulky spin->yield->block/cancel code), and
- * heavily dependent on intrinsics (Unsafe) to use inlined
+ * heavily dependent on intrinsics (VarHandles) to use inlined
* embedded CAS and related memory access operations (that tend
* not to be as readily inlined by dynamic compilers when they are
* hidden behind other methods that would more nicely name and
* encapsulate the intended effects). This includes the use of
- * putXRelease to clear fields of the per-thread Nodes between
+ * setRelease to clear fields of the per-thread Nodes between
* uses. Note that field Node.item is not declared as volatile
* even though it is read by releasing threads, because they only
* do so after CAS operations that must precede access, and all
@@ -252,10 +254,10 @@ public class Exchanger {
*/
/**
- * The byte distance (as a shift value) between any two used slots
- * in the arena. 1 << ASHIFT should be at least cacheline size.
+ * The index distance (as a shift value) between any two used slots
+ * in the arena, spacing them out to avoid false sharing.
*/
- private static final int ASHIFT = 7;
+ private static final int ASHIFT = 5;
/**
* The maximum supported arena index. The maximum allocatable
@@ -356,27 +358,31 @@ public class Exchanger {
*/
private final Object arenaExchange(Object item, boolean timed, long ns) {
Node[] a = arena;
+ int alen = a.length;
Node p = participant.get();
for (int i = p.index;;) { // access slot at i
- int b, m, c; long j; // j is raw array offset
- Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
- if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+ int b, m, c;
+ int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
+ if (j < 0 || j >= alen)
+ j = alen - 1;
+ Node q = (Node)AA.getAcquire(a, j);
+ if (q != null && AA.compareAndSet(a, j, q, null)) {
Object v = q.item; // release
q.match = item;
Thread w = q.parked;
if (w != null)
- U.unpark(w);
+ LockSupport.unpark(w);
return v;
}
else if (i <= (m = (b = bound) & MMASK) && q == null) {
p.item = item; // offer
- if (U.compareAndSwapObject(a, j, null, p)) {
+ if (AA.compareAndSet(a, j, null, p)) {
long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
Thread t = Thread.currentThread(); // wait
for (int h = p.hash, spins = SPINS;;) {
Object v = p.match;
if (v != null) {
- U.putObjectRelease(p, MATCH, null);
+ MATCH.setRelease(p, null);
p.item = null; // clear for next use
p.hash = h;
return v;
@@ -389,22 +395,24 @@ public class Exchanger {
(--spins & ((SPINS >>> 1) - 1)) == 0)
Thread.yield(); // two yields per wait
}
- else if (U.getObjectVolatile(a, j) != p)
+ else if (AA.getAcquire(a, j) != p)
spins = SPINS; // releaser hasn't set match yet
else if (!t.isInterrupted() && m == 0 &&
(!timed ||
(ns = end - System.nanoTime()) > 0L)) {
- U.putObject(t, BLOCKER, this); // emulate LockSupport
p.parked = t; // minimize window
- if (U.getObjectVolatile(a, j) == p)
- U.park(false, ns);
+ if (AA.getAcquire(a, j) == p) {
+ if (ns == 0L)
+ LockSupport.park(this);
+ else
+ LockSupport.parkNanos(this, ns);
+ }
p.parked = null;
- U.putObject(t, BLOCKER, null);
}
- else if (U.getObjectVolatile(a, j) == p &&
- U.compareAndSwapObject(a, j, p, null)) {
+ else if (AA.getAcquire(a, j) == p &&
+ AA.compareAndSet(a, j, p, null)) {
if (m != 0) // try to shrink
- U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+ BOUND.compareAndSet(this, b, b + SEQ - 1);
p.item = null;
p.hash = h;
i = p.index >>>= 1; // descend
@@ -426,7 +434,7 @@ public class Exchanger {
i = (i != m || m == 0) ? m : m - 1;
}
else if ((c = p.collides) < m || m == FULL ||
- !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+ !BOUND.compareAndSet(this, b, b + SEQ + 1)) {
p.collides = c + 1;
i = (i == 0) ? m : i - 1; // cyclically traverse
}
@@ -455,24 +463,24 @@ public class Exchanger {
for (Node q;;) {
if ((q = slot) != null) {
- if (U.compareAndSwapObject(this, SLOT, q, null)) {
+ if (SLOT.compareAndSet(this, q, null)) {
Object v = q.item;
q.match = item;
Thread w = q.parked;
if (w != null)
- U.unpark(w);
+ LockSupport.unpark(w);
return v;
}
// create arena on contention, but continue until slot null
if (NCPU > 1 && bound == 0 &&
- U.compareAndSwapInt(this, BOUND, 0, SEQ))
+ BOUND.compareAndSet(this, 0, SEQ))
arena = new Node[(FULL + 2) << ASHIFT];
}
else if (arena != null)
return null; // caller must reroute to arenaExchange
else {
p.item = item;
- if (U.compareAndSwapObject(this, SLOT, null, p))
+ if (SLOT.compareAndSet(this, null, p))
break;
p.item = null;
}
@@ -495,19 +503,21 @@ public class Exchanger {
spins = SPINS;
else if (!t.isInterrupted() && arena == null &&
(!timed || (ns = end - System.nanoTime()) > 0L)) {
- U.putObject(t, BLOCKER, this);
p.parked = t;
- if (slot == p)
- U.park(false, ns);
+ if (slot == p) {
+ if (ns == 0L)
+ LockSupport.park(this);
+ else
+ LockSupport.parkNanos(this, ns);
+ }
p.parked = null;
- U.putObject(t, BLOCKER, null);
}
- else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+ else if (SLOT.compareAndSet(this, p, null)) {
v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
break;
}
}
- U.putObjectRelease(p, MATCH, null);
+ MATCH.setRelease(p, null);
p.item = null;
p.hash = h;
return v;
@@ -556,8 +566,9 @@ public class Exchanger {
@SuppressWarnings("unchecked")
public V exchange(V x) throws InterruptedException {
Object v;
+ Node[] a;
Object item = (x == null) ? NULL_ITEM : x; // translate null args
- if ((arena != null ||
+ if (((a = arena) != null ||
(v = slotExchange(item, false, 0L)) == null) &&
((Thread.interrupted() || // disambiguates null return
(v = arenaExchange(item, false, 0L)) == null)))
@@ -623,31 +634,18 @@ public class Exchanger {
return (v == NULL_ITEM) ? null : (V)v;
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long BOUND;
- private static final long SLOT;
- private static final long MATCH;
- private static final long BLOCKER;
- private static final int ABASE;
+ // VarHandle mechanics
+ private static final VarHandle BOUND;
+ private static final VarHandle SLOT;
+ private static final VarHandle MATCH;
+ private static final VarHandle AA;
static {
try {
- BOUND = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("bound"));
- SLOT = U.objectFieldOffset
- (Exchanger.class.getDeclaredField("slot"));
-
- MATCH = U.objectFieldOffset
- (Node.class.getDeclaredField("match"));
-
- BLOCKER = U.objectFieldOffset
- (Thread.class.getDeclaredField("parkBlocker"));
-
- int scale = U.arrayIndexScale(Node[].class);
- if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
- throw new Error("Unsupported array scale");
- // ABASE absorbs padding in front of element 0
- ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
+ SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
+ MATCH = l.findVarHandle(Node.class, "match", Object.class);
+ AA = MethodHandles.arrayElementVarHandle(Node[].class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java b/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java
index aade083ffe3..82e773c7630 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
@@ -69,9 +71,6 @@ public class FutureTask implements RunnableFuture {
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
- *
- * Style note: As usual, we bypass overhead of using
- * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
@@ -163,9 +162,8 @@ public class FutureTask implements RunnableFuture {
}
public boolean cancel(boolean mayInterruptIfRunning) {
- if (!(state == NEW &&
- U.compareAndSwapInt(this, STATE, NEW,
- mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+ if (!(state == NEW && STATE.compareAndSet
+ (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
@@ -174,7 +172,7 @@ public class FutureTask implements RunnableFuture {
if (t != null)
t.interrupt();
} finally { // final state
- U.putIntRelease(this, STATE, INTERRUPTED);
+ STATE.setRelease(this, INTERRUPTED);
}
}
} finally {
@@ -228,9 +226,9 @@ public class FutureTask implements RunnableFuture {
* @param v the value
*/
protected void set(V v) {
- if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+ if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = v;
- U.putIntRelease(this, STATE, NORMAL); // final state
+ STATE.setRelease(this, NORMAL); // final state
finishCompletion();
}
}
@@ -246,16 +244,16 @@ public class FutureTask implements RunnableFuture {
* @param t the cause of failure
*/
protected void setException(Throwable t) {
- if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+ if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = t;
- U.putIntRelease(this, STATE, EXCEPTIONAL); // final state
+ STATE.setRelease(this, EXCEPTIONAL); // final state
finishCompletion();
}
}
public void run() {
if (state != NEW ||
- !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+ !RUNNER.compareAndSet(this, null, Thread.currentThread()))
return;
try {
Callable c = callable;
@@ -296,7 +294,7 @@ public class FutureTask implements RunnableFuture {
*/
protected boolean runAndReset() {
if (state != NEW ||
- !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+ !RUNNER.compareAndSet(this, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
@@ -363,7 +361,7 @@ public class FutureTask implements RunnableFuture {
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
- if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+ if (WAITERS.weakCompareAndSetVolatile(this, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
@@ -425,8 +423,7 @@ public class FutureTask implements RunnableFuture {
q = new WaitNode();
}
else if (!queued)
- queued = U.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
+ queued = WAITERS.weakCompareAndSetVolatile(this, q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) { // first time
@@ -475,7 +472,7 @@ public class FutureTask implements RunnableFuture {
if (pred.thread == null) // check for race
continue retry;
}
- else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+ else if (!WAITERS.compareAndSet(this, q, s))
continue retry;
}
break;
@@ -483,19 +480,16 @@ public class FutureTask implements RunnableFuture {
}
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long RUNNER;
- private static final long WAITERS;
+ // VarHandle mechanics
+ private static final VarHandle STATE;
+ private static final VarHandle RUNNER;
+ private static final VarHandle WAITERS;
static {
try {
- STATE = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("state"));
- RUNNER = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("runner"));
- WAITERS = U.objectFieldOffset
- (FutureTask.class.getDeclaredField("waiters"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(FutureTask.class, "state", int.class);
+ RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
+ WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java
index 69b9a694f85..cb613e3f092 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@@ -444,7 +446,7 @@ public class LinkedTransferQueue extends AbstractQueue
/**
* Queue nodes. Uses Object, not E, for items to allow forgetting
- * them after use. Relies heavily on Unsafe mechanics to minimize
+ * them after use. Relies heavily on VarHandles to minimize
* unnecessary ordering constraints: Writes that are intrinsically
* ordered wrt other accesses or CASes use simple relaxed forms.
*/
@@ -456,12 +458,12 @@ public class LinkedTransferQueue extends AbstractQueue
// CAS methods for fields
final boolean casNext(Node cmp, Node val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return NEXT.compareAndSet(this, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class;
- return U.compareAndSwapObject(this, ITEM, cmp, val);
+ return ITEM.compareAndSet(this, cmp, val);
}
/**
@@ -469,7 +471,7 @@ public class LinkedTransferQueue extends AbstractQueue
* only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
- U.putObject(this, ITEM, item); // relaxed write
+ ITEM.set(this, item); // relaxed write
this.isData = isData;
}
@@ -478,7 +480,7 @@ public class LinkedTransferQueue extends AbstractQueue
* only after CASing head field, so uses relaxed write.
*/
final void forgetNext() {
- U.putObject(this, NEXT, this);
+ NEXT.set(this, this);
}
/**
@@ -491,8 +493,8 @@ public class LinkedTransferQueue extends AbstractQueue
* else we don't care).
*/
final void forgetContents() {
- U.putObject(this, ITEM, this);
- U.putObject(this, WAITER, null);
+ ITEM.set(this, this);
+ WAITER.set(this, null);
}
/**
@@ -537,19 +539,16 @@ public class LinkedTransferQueue extends AbstractQueue
private static final long serialVersionUID = -3375979862319811754L;
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long ITEM;
- private static final long NEXT;
- private static final long WAITER;
+ // VarHandle mechanics
+ private static final VarHandle ITEM;
+ private static final VarHandle NEXT;
+ private static final VarHandle WAITER;
static {
try {
- ITEM = U.objectFieldOffset
- (Node.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- WAITER = U.objectFieldOffset
- (Node.class.getDeclaredField("waiter"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ ITEM = l.findVarHandle(Node.class, "item", Object.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -567,15 +566,15 @@ public class LinkedTransferQueue extends AbstractQueue
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
+ return TAIL.compareAndSet(this, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return HEAD.compareAndSet(this, cmp, val);
}
private boolean casSweepVotes(int cmp, int val) {
- return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+ return SWEEPVOTES.compareAndSet(this, cmp, val);
}
/*
@@ -1562,20 +1561,19 @@ public class LinkedTransferQueue extends AbstractQueue
}
}
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long HEAD;
- private static final long TAIL;
- private static final long SWEEPVOTES;
+ // VarHandle mechanics
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
+ private static final VarHandle SWEEPVOTES;
static {
try {
- HEAD = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("tail"));
- SWEEPVOTES = U.objectFieldOffset
- (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
+ Node.class);
+ TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
+ Node.class);
+ SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
+ int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java
index 3fd30e7d3a8..c0e6fbadb01 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
@@ -221,7 +223,6 @@ import java.util.concurrent.locks.LockSupport;
* phaser.arriveAndDeregister();
* }}
*
- *
* To create a set of {@code n} tasks using a tree of phasers, you
* could use code of the following form, assuming a Task class with a
* constructor accepting a {@code Phaser} that it registers with upon
@@ -384,7 +385,7 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+ if (STATE.compareAndSet(this, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@@ -397,12 +398,12 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- U.compareAndSwapLong(this, STATE, s, n);
+ STATE.compareAndSet(this, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
- U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+ STATE.compareAndSet(this, s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@@ -437,13 +438,13 @@ public class Phaser {
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
- else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+ else if (STATE.compareAndSet(this, s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
- if (U.compareAndSwapLong(this, STATE, s, next))
+ if (STATE.compareAndSet(this, s, next))
break;
}
else {
@@ -455,8 +456,8 @@ public class Phaser {
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
- while (!U.compareAndSwapLong
- (this, STATE, s,
+ while (!STATE.weakCompareAndSetVolatile
+ (this, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@@ -487,8 +488,8 @@ public class Phaser {
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
- !U.compareAndSwapLong
- (this, STATE, s,
+ !STATE.weakCompareAndSetVolatile
+ (this, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@@ -677,7 +678,7 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
- if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+ if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@@ -692,7 +693,7 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
- if (!U.compareAndSwapLong(this, STATE, s, n))
+ if (!STATE.compareAndSet(this, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@@ -808,7 +809,7 @@ public class Phaser {
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
- if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+ if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@@ -1043,6 +1044,8 @@ public class Phaser {
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
+ else
+ Thread.onSpinWait();
}
else if (node.isReleasable()) // done or aborted
break;
@@ -1131,14 +1134,12 @@ public class Phaser {
}
}
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long STATE;
+ // VarHandle mechanics
+ private static final VarHandle STATE;
static {
try {
- STATE = U.objectFieldOffset
- (Phaser.class.getDeclaredField("state"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(Phaser.class, "state", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java
index 652fd6958cf..36f5a47e3f9 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java
@@ -35,6 +35,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@@ -289,7 +291,7 @@ public class PriorityBlockingQueue extends AbstractQueue
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
- U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+ ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@@ -1009,13 +1011,14 @@ public class PriorityBlockingQueue extends AbstractQueue
return new PBQSpliterator(this, null, 0, -1);
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long ALLOCATIONSPINLOCK;
+ // VarHandle mechanics
+ private static final VarHandle ALLOCATIONSPINLOCK;
static {
try {
- ALLOCATIONSPINLOCK = U.objectFieldOffset
- (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
+ "allocationSpinLock",
+ int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java b/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java
index 069d0a6b851..e12d7afecc6 100644
--- a/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java
@@ -36,6 +36,8 @@
package java.util.concurrent;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Collections;
@@ -247,7 +249,7 @@ public class SynchronousQueue extends AbstractQueue
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ SNEXT.compareAndSet(this, cmp, val);
}
/**
@@ -260,7 +262,7 @@ public class SynchronousQueue extends AbstractQueue
*/
boolean tryMatch(SNode s) {
if (match == null &&
- U.compareAndSwapObject(this, MATCH, null, s)) {
+ SMATCH.compareAndSet(this, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@@ -275,24 +277,21 @@ public class SynchronousQueue extends AbstractQueue
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
- U.compareAndSwapObject(this, MATCH, null, this);
+ SMATCH.compareAndSet(this, null, this);
}
boolean isCancelled() {
return match == this;
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long MATCH;
- private static final long NEXT;
-
+ // VarHandle mechanics
+ private static final VarHandle SMATCH;
+ private static final VarHandle SNEXT;
static {
try {
- MATCH = U.objectFieldOffset
- (SNode.class.getDeclaredField("match"));
- NEXT = U.objectFieldOffset
- (SNode.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
+ SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -304,7 +303,7 @@ public class SynchronousQueue extends AbstractQueue
boolean casHead(SNode h, SNode nh) {
return h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh);
+ SHEAD.compareAndSet(this, h, nh);
}
/**
@@ -451,8 +450,10 @@ public class SynchronousQueue extends AbstractQueue
continue;
}
}
- if (spins > 0)
+ if (spins > 0) {
+ Thread.onSpinWait();
spins = shouldSpin(s) ? (spins - 1) : 0;
+ }
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
@@ -508,13 +509,12 @@ public class SynchronousQueue extends AbstractQueue
}
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long HEAD;
+ // VarHandle mechanics
+ private static final VarHandle SHEAD;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferStack.class.getDeclaredField("head"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -546,19 +546,19 @@ public class SynchronousQueue extends AbstractQueue
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ QNEXT.compareAndSet(this, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
- U.compareAndSwapObject(this, ITEM, cmp, val);
+ QITEM.compareAndSet(this, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
- U.compareAndSwapObject(this, ITEM, cmp, this);
+ QITEM.compareAndSet(this, cmp, this);
}
boolean isCancelled() {
@@ -574,17 +574,14 @@ public class SynchronousQueue extends AbstractQueue