8080603: Replace Unsafe with VarHandle in java.util.concurrent classes
8153715: Use Unsafe.weakCompareAndSet in java.util.concurrent
Reviewed-by: martin, psandoz, rriggs, plevart, dfuchs, shade
--- a/jdk/src/java.base/share/classes/java/util/Queue.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Queue.java Fri Jul 15 14:04:09 2016 -0700
@@ -124,7 +124,6 @@
* always well-defined for queues with the same elements but different
* ordering properties.
*
- *
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Fri Jul 15 14:04:09 2016 -0700
@@ -68,6 +68,7 @@
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 @@
/* ---------------- 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 @@
* 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 <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
- return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+ return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
@@ -773,7 +772,7 @@
}
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
- U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+ U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
}
/* ---------------- Fields -------------- */
@@ -3298,7 +3297,7 @@
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 @@
}
// 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;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
volatile Node<E> prev;
volatile E item;
volatile Node<E> 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<E> val) {
- U.putObjectRelease(this, NEXT, val);
- }
-
- boolean casNext(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
- }
+ }
- void lazySetPrev(Node<E> val) {
- U.putObjectRelease(this, PREV, val);
- }
-
- boolean casPrev(Node<E> cmp, Node<E> 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 <E> Node<E> newNode(E item) {
+ Node<E> node = new Node<E>();
+ ITEM.set(node, item);
+ return node;
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromHead:
for (;;)
@@ -363,13 +324,13 @@
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 @@
* Links e as last element.
*/
private void linkLast(E e) {
- final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromTail:
for (;;)
@@ -395,13 +356,13 @@
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 @@
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 @@
// assert first.item == null;
for (Node<E> 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 @@
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 @@
// assert last.item == null;
for (Node<E> 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 @@
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 @@
(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 @@
(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 @@
}
// 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 @@
}
// 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 @@
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 @@
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 @@
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
- head = tail = new Node<E>(null);
+ head = tail = new Node<E>();
}
/**
@@ -818,12 +781,12 @@
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
for (E e : c) {
- Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ Node<E> 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 @@
private void initHeadTail(Node<E> h, Node<E> t) {
if (h == t) {
if (h == null)
- h = t = new Node<E>(null);
+ h = t = new Node<E>();
else {
// Avoid edge case of a single Node with non-null item.
- Node<E> newNode = new Node<E>(null);
- t.lazySetNext(newNode);
- newNode.lazySetPrev(t);
+ Node<E> newNode = new Node<E>();
+ NEXT.set(t, newNode);
+ PREV.set(newNode, t);
t = newNode;
}
}
@@ -934,7 +897,7 @@
public E pollFirst() {
for (Node<E> 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 E pollLast() {
for (Node<E> 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 @@
Objects.requireNonNull(o);
for (Node<E> 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 @@
Objects.requireNonNull(o);
for (Node<E> 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 @@
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
- Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+ Node<E> 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 @@
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 @@
Node<E> h = null, t = null;
for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
- Node<E> newNode = new Node<E>((E) item);
+ Node<E> 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<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
- }
-
- private boolean casTail(Node<E> cmp, Node<E> 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<Object>();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>();
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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* 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 @@
* optimization.
*/
- private static class Node<E> {
+ static final class Node<E> {
volatile E item;
volatile Node<E> 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 <E> Node<E> newNode(E item) {
Node<E> node = new Node<E>();
- U.putObject(node, ITEM, item);
+ ITEM.set(node, item);
return node;
}
- static <E> boolean casItem(Node<E> node, E cmp, E val) {
- return U.compareAndSwapObject(node, ITEM, cmp, val);
- }
-
- static <E> void lazySetNext(Node<E> node, Node<E> val) {
- U.putObjectRelease(node, NEXT, val);
- }
-
- static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> 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 @@
if (h == null)
h = t = newNode;
else {
- lazySetNext(t, newNode);
+ NEXT.set(t, newNode);
t = newNode;
}
}
@@ -286,8 +275,8 @@
*/
final void updateHead(Node<E> h, Node<E> 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 @@
Node<E> 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 @@
for (Node<E> 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 @@
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 @@
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
- lazySetNext(last, newNode);
+ NEXT.set(last, newNode);
last = newNode;
}
}
@@ -532,15 +521,15 @@
Node<E> 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 @@
}
// unlink deleted nodes
if ((q = succ(p)) != null)
- casNext(pred, p, q);
+ NEXT.compareAndSet(pred, p, q);
}
}
@@ -801,7 +790,7 @@
if (h == null)
h = t = newNode;
else {
- lazySetNext(t, newNode);
+ NEXT.set(t, newNode);
t = newNode;
}
}
@@ -919,31 +908,20 @@
return new CLQSpliterator<E>(this);
}
- private boolean casTail(Node<E> cmp, Node<E> val) {
- return U.compareAndSwapObject(this, TAIL, cmp, val);
- }
-
- private boolean casHead(Node<E> cmp, Node<E> 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* compareAndSet head node.
*/
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
- return U.compareAndSwapObject(this, HEAD, cmp, val);
+ return HEAD.compareAndSet(this, cmp, val);
}
/* ---------------- Nodes -------------- */
@@ -444,14 +446,14 @@
* 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<K,V> cmp, Node<K,V> val) {
- return U.compareAndSwapObject(this, NEXT, cmp, val);
+ return NEXT.compareAndSet(this, cmp, val);
}
/**
@@ -532,20 +534,16 @@
return new AbstractMap.SimpleImmutableEntry<K,V>(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 @@
* compareAndSet right field.
*/
final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
- return U.compareAndSwapObject(this, RIGHT, cmp, val);
+ return RIGHT.compareAndSet(this, cmp, val);
}
/**
@@ -613,13 +611,12 @@
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 @@
}
}
- // 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
// Support for resetting map in clone
private void setMap(ConcurrentNavigableMap<E,Object> 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
}
}
- // 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<Field>) () -> {
+ 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);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* @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 @@
* @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 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 @@
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@@ -604,7 +607,7 @@
return;
}
}
- else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+ else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@@ -649,7 +652,7 @@
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 @@
*/
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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* 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 @@
* 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 @@
*/
/**
- * 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 @@
*/
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 @@
(--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 @@
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 @@
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 @@
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 @@
@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 @@
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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/FutureTask.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* 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 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 @@
if (t != null)
t.interrupt();
} finally { // final state
- U.putIntRelease(this, STATE, INTERRUPTED);
+ STATE.setRelease(this, INTERRUPTED);
}
}
} finally {
@@ -228,9 +226,9 @@
* @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 @@
* @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<V> c = callable;
@@ -296,7 +294,7 @@
*/
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 @@
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 @@
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 @@
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 @@
}
}
- // 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
/**
* 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 @@
// 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 @@
* 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 @@
* 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 @@
* 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 @@
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 @@
// 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 @@
}
}
- // 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
* phaser.arriveAndDeregister();
* }}</pre>
*
- *
* <p>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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- // 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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
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 @@
return new PBQSpliterator<E>(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);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Fri Jul 15 14:04:09 2016 -0700
@@ -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 @@
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
- U.compareAndSwapObject(this, NEXT, cmp, val);
+ SNEXT.compareAndSet(this, cmp, val);
}
/**
@@ -260,7 +262,7 @@
*/
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 @@
* 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 @@
boolean casHead(SNode h, SNode nh) {
return h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh);
+ SHEAD.compareAndSet(this, h, nh);
}
/**
@@ -451,8 +450,10 @@
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 @@
}
}
- // 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 @@
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 @@
return next == this;
}
- // 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;
-
+ // VarHandle mechanics
+ private static final VarHandle QITEM;
+ private static final VarHandle QNEXT;
static {
try {
- ITEM = U.objectFieldOffset
- (QNode.class.getDeclaredField("item"));
- NEXT = U.objectFieldOffset
- (QNode.class.getDeclaredField("next"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ QITEM = l.findVarHandle(QNode.class, "item", Object.class);
+ QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -614,7 +611,7 @@
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
- U.compareAndSwapObject(this, HEAD, h, nh))
+ QHEAD.compareAndSet(this, h, nh))
h.next = h; // forget old next
}
@@ -623,7 +620,7 @@
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
- U.compareAndSwapObject(this, TAIL, t, nt);
+ QTAIL.compareAndSet(this, t, nt);
}
/**
@@ -631,7 +628,7 @@
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
- U.compareAndSwapObject(this, CLEANME, cmp, val);
+ QCLEANME.compareAndSet(this, cmp, val);
}
/**
@@ -752,8 +749,10 @@
continue;
}
}
- if (spins > 0)
+ if (spins > 0) {
--spins;
+ Thread.onSpinWait();
+ }
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
@@ -817,18 +816,19 @@
}
}
- 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 CLEANME;
+ // VarHandle mechanics
+ private static final VarHandle QHEAD;
+ private static final VarHandle QTAIL;
+ private static final VarHandle QCLEANME;
static {
try {
- HEAD = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("tail"));
- CLEANME = U.objectFieldOffset
- (TransferQueue.class.getDeclaredField("cleanMe"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ QHEAD = l.findVarHandle(TransferQueue.class, "head",
+ QNode.class);
+ QTAIL = l.findVarHandle(TransferQueue.class, "tail",
+ QNode.class);
+ QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
+ QNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,27 +35,26 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* A {@code boolean} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicBoolean} is used in applications such as atomically
- * updated flags, and cannot be used as a replacement for a
- * {@link java.lang.Boolean}.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicBoolean} is used in
+ * applications such as atomically updated flags, and cannot be used
+ * as a replacement for a {@link java.lang.Boolean}.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicBoolean implements java.io.Serializable {
private static final long serialVersionUID = 4654671469794556979L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
-
+ private static final VarHandle VALUE;
static {
try {
- VALUE = U.objectFieldOffset
- (AtomicBoolean.class.getDeclaredField("value"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -79,7 +78,8 @@
}
/**
- * Returns the current value.
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@@ -88,40 +88,39 @@
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
+ public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
+ return VALUE.compareAndSet(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0));
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
- *
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public boolean weakCompareAndSet(boolean expect, boolean update) {
- return U.compareAndSwapInt(this, VALUE,
- (expect ? 1 : 0),
- (update ? 1 : 0));
+ public boolean weakCompareAndSet(boolean expectedValue, boolean newValue) {
+ return VALUE.weakCompareAndSet(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0));
}
/**
- * Unconditionally sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@@ -130,17 +129,19 @@
}
/**
- * Eventually sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(boolean newValue) {
- U.putIntRelease(this, VALUE, (newValue ? 1 : 0));
+ VALUE.setRelease(this, (newValue ? 1 : 0));
}
/**
- * Atomically sets to the given value and returns the previous value.
+ * Atomically sets the value to {@code newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
@@ -161,4 +162,178 @@
return Boolean.toString(get());
}
+ // jdk9
+
+ /**
+ * Returns the current value, with memory semantics of reading as
+ * if the variable was declared non-{@code volatile}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final boolean getPlain() {
+ return (int)VALUE.get(this) != 0;
+ }
+
+ /**
+ * Sets the value to {@code newValue}, with memory semantics
+ * of setting as if the variable was declared non-{@code volatile}
+ * and non-{@code final}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(boolean newValue) {
+ VALUE.set(this, newValue ? 1 : 0);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final boolean getOpaque() {
+ return (int)VALUE.getOpaque(this) != 0;
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(boolean newValue) {
+ VALUE.setOpaque(this, newValue ? 1 : 0);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final boolean getAcquire() {
+ return (int)VALUE.getAcquire(this) != 0;
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(boolean newValue) {
+ VALUE.setRelease(this, newValue ? 1 : 0);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final boolean compareAndExchange(boolean expectedValue, boolean newValue) {
+ return (int)VALUE.compareAndExchange(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0)) != 0;
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final boolean compareAndExchangeAcquire(boolean expectedValue, boolean newValue) {
+ return (int)VALUE.compareAndExchangeAcquire(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0)) != 0;
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final boolean compareAndExchangeRelease(boolean expectedValue, boolean newValue) {
+ return (int)VALUE.compareAndExchangeRelease(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0)) != 0;
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if the current
+ * value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(boolean expectedValue, boolean newValue) {
+ return VALUE.weakCompareAndSetVolatile(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0));
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if the current
+ * value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(boolean expectedValue, boolean newValue) {
+ return VALUE.weakCompareAndSetAcquire(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0));
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if the current
+ * value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(boolean expectedValue, boolean newValue) {
+ return VALUE.weakCompareAndSetRelease(this,
+ (expectedValue ? 1 : 0),
+ (newValue ? 1 : 0));
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,32 +35,30 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
/**
* An {@code int} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicInteger} is used in applications such as atomically
- * incremented counters, and cannot be used as a replacement for an
- * {@link java.lang.Integer}. However, this class does extend
- * {@code Number} to allow uniform access by tools and utilities that
- * deal with numerically-based classes.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicInteger} is used in
+ * applications such as atomically incremented counters, and cannot be
+ * used as a replacement for an {@link java.lang.Integer}. However,
+ * this class does extend {@code Number} to allow uniform access by
+ * tools and utilities that deal with numerically-based classes.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
-
+ private static final VarHandle VALUE;
static {
try {
- VALUE = U.objectFieldOffset
- (AtomicInteger.class.getDeclaredField("value"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(AtomicInteger.class, "value", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -84,7 +82,8 @@
}
/**
- * Gets the current value.
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@@ -93,7 +92,8 @@
}
/**
- * Sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@@ -102,108 +102,122 @@
}
/**
- * Eventually sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int newValue) {
- U.putIntRelease(this, VALUE, newValue);
+ VALUE.setRelease(this, newValue);
}
/**
- * Atomically sets to the given value and returns the old value.
+ * Atomically sets the value to {@code newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
- return U.getAndSetInt(this, VALUE, newValue);
+ return (int)VALUE.getAndSet(this, newValue);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(int expect, int update) {
- return U.compareAndSwapInt(this, VALUE, expect, update);
+ public final boolean compareAndSet(int expectedValue, int newValue) {
+ return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
- *
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public final boolean weakCompareAndSet(int expect, int update) {
- return U.compareAndSwapInt(this, VALUE, expect, update);
+ public final boolean weakCompareAndSet(int expectedValue, int newValue) {
+ return VALUE.weakCompareAndSet(this, expectedValue, newValue);
}
/**
- * Atomically increments by one the current value.
+ * Atomically increments the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(1)}.
*
* @return the previous value
*/
public final int getAndIncrement() {
- return U.getAndAddInt(this, VALUE, 1);
+ return (int)VALUE.getAndAdd(this, 1);
}
/**
- * Atomically decrements by one the current value.
+ * Atomically decrements the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(-1)}.
*
* @return the previous value
*/
public final int getAndDecrement() {
- return U.getAndAddInt(this, VALUE, -1);
+ return (int)VALUE.getAndAdd(this, -1);
}
/**
- * Atomically adds the given value to the current value.
+ * Atomically adds the given value to the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
- return U.getAndAddInt(this, VALUE, delta);
+ return (int)VALUE.getAndAdd(this, delta);
}
/**
- * Atomically increments by one the current value.
+ * Atomically increments the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(1)}.
*
* @return the updated value
*/
public final int incrementAndGet() {
- return U.getAndAddInt(this, VALUE, 1) + 1;
+ return (int)VALUE.addAndGet(this, 1);
}
/**
- * Atomically decrements by one the current value.
+ * Atomically decrements the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(-1)}.
*
* @return the updated value
*/
public final int decrementAndGet() {
- return U.getAndAddInt(this, VALUE, -1) - 1;
+ return (int)VALUE.addAndGet(this, -1);
}
/**
- * Atomically adds the given value to the current value.
+ * Atomically adds the given value to the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
- return U.getAndAddInt(this, VALUE, delta) + delta;
+ return (int)VALUE.addAndGet(this, delta);
}
/**
@@ -217,12 +231,14 @@
* @since 1.8
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(prev, next));
- return prev;
+ int prev = get(), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsInt(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -236,12 +252,14 @@
* @since 1.8
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(prev, next));
- return next;
+ int prev = get(), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsInt(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -260,12 +278,14 @@
*/
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
+ int prev = get(), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsInt(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -284,12 +304,14 @@
*/
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
- int prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ int prev = get(), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsInt(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -301,7 +323,10 @@
}
/**
- * Returns the value of this {@code AtomicInteger} as an {@code int}.
+ * Returns the current value of this {@code AtomicInteger} as an
+ * {@code int},
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
+ *
* Equivalent to {@link #get()}.
*/
public int intValue() {
@@ -309,8 +334,9 @@
}
/**
- * Returns the value of this {@code AtomicInteger} as a {@code long}
- * after a widening primitive conversion.
+ * Returns the current value of this {@code AtomicInteger} as a
+ * {@code long} after a widening primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public long longValue() {
@@ -318,8 +344,9 @@
}
/**
- * Returns the value of this {@code AtomicInteger} as a {@code float}
- * after a widening primitive conversion.
+ * Returns the current value of this {@code AtomicInteger} as a
+ * {@code float} after a widening primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
@@ -327,12 +354,175 @@
}
/**
- * Returns the value of this {@code AtomicInteger} as a {@code double}
- * after a widening primitive conversion.
+ * Returns the current value of this {@code AtomicInteger} as a
+ * {@code double} after a widening primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
}
+ // jdk9
+
+ /**
+ * Returns the current value, with memory semantics of reading as
+ * if the variable was declared non-{@code volatile}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final int getPlain() {
+ return (int)VALUE.get(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue}, with memory semantics
+ * of setting as if the variable was declared non-{@code volatile}
+ * and non-{@code final}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(int newValue) {
+ VALUE.set(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final int getOpaque() {
+ return (int)VALUE.getOpaque(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(int newValue) {
+ VALUE.setOpaque(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final int getAcquire() {
+ return (int)VALUE.getAcquire(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(int newValue) {
+ VALUE.setRelease(this, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchange(int expectedValue, int newValue) {
+ return (int)VALUE.compareAndExchange(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
+ return (int)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchangeRelease(int expectedValue, int newValue) {
+ return (int)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if
+ * the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
+ return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if
+ * the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
+ return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue} if
+ * the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
+ return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,44 +35,24 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
/**
* An {@code int} array in which elements may be updated atomically.
- * See the {@link java.util.concurrent.atomic} package
- * specification for description of the properties of atomic
- * variables.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
* @since 1.5
* @author Doug Lea
*/
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final VarHandle AA
+ = MethodHandles.arrayElementVarHandle(int[].class);
private final int[] array;
- static {
- ABASE = U.arrayBaseOffset(int[].class);
- int scale = U.arrayIndexScale(int[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- }
-
- private long checkedByteOffset(int i) {
- if (i < 0 || i >= array.length)
- throw new IndexOutOfBoundsException("index " + i);
-
- return byteOffset(i);
- }
-
- private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
- }
-
/**
* Creates a new AtomicIntegerArray of the given length, with all
* elements initially zero.
@@ -105,147 +85,155 @@
}
/**
- * Gets the current value at position {@code i}.
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
public final int get(int i) {
- return getRaw(checkedByteOffset(i));
- }
-
- private int getRaw(long offset) {
- return U.getIntVolatile(array, offset);
+ return (int)AA.getVolatile(array, i);
}
/**
- * Sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, int newValue) {
- U.putIntVolatile(array, checkedByteOffset(i), newValue);
+ AA.setVolatile(array, i, newValue);
}
/**
- * Eventually sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, int newValue) {
- U.putIntRelease(array, checkedByteOffset(i), newValue);
+ AA.setRelease(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * value and returns the old value.
+ * Atomically sets the element at index {@code i} to {@code
+ * newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int i, int newValue) {
- return U.getAndSetInt(array, checkedByteOffset(i), newValue);
+ return (int)AA.getAndSet(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
+ * Atomically sets the element at index {@code i} to {@code
+ * newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(int i, int expect, int update) {
- return compareAndSetRaw(checkedByteOffset(i), expect, update);
- }
-
- private boolean compareAndSetRaw(long offset, int expect, int update) {
- return U.compareAndSwapInt(array, offset, expect, update);
+ public final boolean compareAndSet(int i, int expectedValue, int newValue) {
+ return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
- *
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public final boolean weakCompareAndSet(int i, int expect, int update) {
- return compareAndSet(i, expect, update);
+ public final boolean weakCompareAndSet(int i, int expectedValue, int newValue) {
+ return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
- * Atomically increments by one the element at index {@code i}.
+ * Atomically increments the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(i, 1)}.
*
* @param i the index
* @return the previous value
*/
public final int getAndIncrement(int i) {
- return getAndAdd(i, 1);
+ return (int)AA.getAndAdd(array, i, 1);
}
/**
- * Atomically decrements by one the element at index {@code i}.
+ * Atomically decrements the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(i, -1)}.
*
* @param i the index
* @return the previous value
*/
public final int getAndDecrement(int i) {
- return getAndAdd(i, -1);
+ return (int)AA.getAndAdd(array, i, -1);
}
/**
- * Atomically adds the given value to the element at index {@code i}.
+ * Atomically adds the given value to the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param i the index
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int i, int delta) {
- return U.getAndAddInt(array, checkedByteOffset(i), delta);
+ return (int)AA.getAndAdd(array, i, delta);
}
/**
- * Atomically increments by one the element at index {@code i}.
+ * Atomically increments the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(i, 1)}.
*
* @param i the index
* @return the updated value
*/
public final int incrementAndGet(int i) {
- return getAndAdd(i, 1) + 1;
+ return (int)AA.addAndGet(array, i, 1);
}
/**
- * Atomically decrements by one the element at index {@code i}.
+ * Atomically decrements the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(i, -1)}.
*
* @param i the index
* @return the updated value
*/
public final int decrementAndGet(int i) {
- return getAndAdd(i, -1) - 1;
+ return (int)AA.addAndGet(array, i, -1);
}
/**
- * Atomically adds the given value to the element at index {@code i}.
+ * Atomically adds the given value to the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param i the index
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int i, int delta) {
- return getAndAdd(i, delta) + delta;
+ return (int)AA.addAndGet(array, i, delta);
}
/**
@@ -260,13 +248,14 @@
* @since 1.8
*/
public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ int prev = get(i), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsInt(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -281,23 +270,25 @@
* @since 1.8
*/
public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ int prev = get(i), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsInt(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the previous value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the previous value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -307,23 +298,25 @@
*/
public final int getAndAccumulate(int i, int x,
IntBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ int prev = get(i), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsInt(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the updated value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the updated value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -333,13 +326,14 @@
*/
public final int accumulateAndGet(int i, int x,
IntBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- int prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsInt(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ int prev = get(i), next = 0;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsInt(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -354,11 +348,190 @@
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
- b.append(getRaw(byteOffset(i)));
+ b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}
+ // jdk9
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory semantics of reading as if the variable was declared
+ * non-{@code volatile}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final int getPlain(int i) {
+ return (int)AA.get(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory semantics of setting as if the variable was
+ * declared non-{@code volatile} and non-{@code final}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(int i, int newValue) {
+ AA.set(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final int getOpaque(int i) {
+ return (int)AA.getOpaque(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(int i, int newValue) {
+ AA.setOpaque(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final int getAcquire(int i) {
+ return (int)AA.getAcquire(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(int i, int newValue) {
+ AA.setRelease(array, i, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchange(int i, int expectedValue, int newValue) {
+ return (int)AA.compareAndExchange(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchangeAcquire(int i, int expectedValue, int newValue) {
+ return (int)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final int compareAndExchangeRelease(int i, int expectedValue, int newValue) {
+ return (int)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(int i, int expectedValue, int newValue) {
+ return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(int i, int expectedValue, int newValue) {
+ return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(int i, int expectedValue, int newValue) {
+ return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+ }
+
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Fri Jul 15 14:04:09 2016 -0700
@@ -42,6 +42,7 @@
import java.security.PrivilegedExceptionAction;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
+import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@@ -150,8 +151,8 @@
public abstract void lazySet(T obj, int newValue);
/**
- * Gets the current value held in the field of the given object managed
- * by this updater.
+ * Returns the current value held in the field of the given object
+ * managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@@ -367,7 +368,7 @@
*/
private static final class AtomicIntegerFieldUpdaterImpl<T>
extends AtomicIntegerFieldUpdater<T> {
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,31 +35,30 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
/**
* A {@code long} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for
- * description of the properties of atomic variables. An
- * {@code AtomicLong} is used in applications such as atomically
- * incremented sequence numbers, and cannot be used as a replacement
- * for a {@link java.lang.Long}. However, this class does extend
- * {@code Number} to allow uniform access by tools and utilities that
- * deal with numerically-based classes.
+ * {@link VarHandle} specification for descriptions of the properties
+ * of atomic accesses. An {@code AtomicLong} is used in applications
+ * such as atomically incremented sequence numbers, and cannot be used
+ * as a replacement for a {@link java.lang.Long}. However, this class
+ * does extend {@code Number} to allow uniform access by tools and
+ * utilities that deal with numerically-based classes.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ private static final VarHandle VALUE;
/**
* Records whether the underlying JVM supports lockless
- * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
+ * compareAndSwap for longs. While the intrinsic compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
@@ -73,8 +72,8 @@
static {
try {
- VALUE = U.objectFieldOffset
- (AtomicLong.class.getDeclaredField("value"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(AtomicLong.class, "value", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -98,7 +97,8 @@
}
/**
- * Gets the current value.
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@@ -107,119 +107,132 @@
}
/**
- * Sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
public final void set(long newValue) {
- // Use putLongVolatile instead of ordinary volatile store when
- // using compareAndSwapLong, for sake of some 32bit systems.
- U.putLongVolatile(this, VALUE, newValue);
+ VALUE.setVolatile(this, newValue);
}
/**
- * Eventually sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(long newValue) {
- U.putLongRelease(this, VALUE, newValue);
+ VALUE.setRelease(this, newValue);
}
/**
- * Atomically sets to the given value and returns the old value.
+ * Atomically sets the value to {@code newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(long newValue) {
- return U.getAndSetLong(this, VALUE, newValue);
+ return (long)VALUE.getAndSet(this, newValue);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(long expect, long update) {
- return U.compareAndSwapLong(this, VALUE, expect, update);
+ public final boolean compareAndSet(long expectedValue, long newValue) {
+ return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
- *
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public final boolean weakCompareAndSet(long expect, long update) {
- return U.compareAndSwapLong(this, VALUE, expect, update);
+ public final boolean weakCompareAndSet(long expectedValue, long newValue) {
+ return VALUE.weakCompareAndSet(this, expectedValue, newValue);
}
/**
- * Atomically increments by one the current value.
+ * Atomically increments the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(1)}.
*
* @return the previous value
*/
public final long getAndIncrement() {
- return U.getAndAddLong(this, VALUE, 1L);
+ return (long)VALUE.getAndAdd(this, 1L);
}
/**
- * Atomically decrements by one the current value.
+ * Atomically decrements the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(-1)}.
*
* @return the previous value
*/
public final long getAndDecrement() {
- return U.getAndAddLong(this, VALUE, -1L);
+ return (long)VALUE.getAndAdd(this, -1L);
}
/**
- * Atomically adds the given value to the current value.
+ * Atomically adds the given value to the current value,
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param delta the value to add
* @return the previous value
*/
public final long getAndAdd(long delta) {
- return U.getAndAddLong(this, VALUE, delta);
+ return (long)VALUE.getAndAdd(this, delta);
}
/**
- * Atomically increments by one the current value.
+ * Atomically increments the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(1)}.
*
* @return the updated value
*/
public final long incrementAndGet() {
- return U.getAndAddLong(this, VALUE, 1L) + 1L;
+ return (long)VALUE.addAndGet(this, 1L);
}
/**
- * Atomically decrements by one the current value.
+ * Atomically decrements the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(-1)}.
*
* @return the updated value
*/
public final long decrementAndGet() {
- return U.getAndAddLong(this, VALUE, -1L) - 1L;
+ return (long)VALUE.addAndGet(this, -1L);
}
/**
- * Atomically adds the given value to the current value.
+ * Atomically adds the given value to the current value,
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param delta the value to add
* @return the updated value
*/
public final long addAndGet(long delta) {
- return U.getAndAddLong(this, VALUE, delta) + delta;
+ return (long)VALUE.addAndGet(this, delta);
}
/**
@@ -233,12 +246,14 @@
* @since 1.8
*/
public final long getAndUpdate(LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(prev, next));
- return prev;
+ long prev = get(), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsLong(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -252,12 +267,14 @@
* @since 1.8
*/
public final long updateAndGet(LongUnaryOperator updateFunction) {
- long prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSet(prev, next));
- return next;
+ long prev = get(), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsLong(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -276,12 +293,14 @@
*/
public final long getAndAccumulate(long x,
LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
+ long prev = get(), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsLong(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -300,12 +319,14 @@
*/
public final long accumulateAndGet(long x,
LongBinaryOperator accumulatorFunction) {
- long prev, next;
- do {
- prev = get();
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ long prev = get(), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsLong(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -317,8 +338,9 @@
}
/**
- * Returns the value of this {@code AtomicLong} as an {@code int}
- * after a narrowing primitive conversion.
+ * Returns the current value of this {@code AtomicLong} as an {@code int}
+ * after a narrowing primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.3 Narrowing Primitive Conversions
*/
public int intValue() {
@@ -326,7 +348,8 @@
}
/**
- * Returns the value of this {@code AtomicLong} as a {@code long}.
+ * Returns the current value of this {@code AtomicLong} as a {@code long},
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* Equivalent to {@link #get()}.
*/
public long longValue() {
@@ -334,8 +357,9 @@
}
/**
- * Returns the value of this {@code AtomicLong} as a {@code float}
- * after a widening primitive conversion.
+ * Returns the current value of this {@code AtomicLong} as a {@code float}
+ * after a widening primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
@@ -343,12 +367,175 @@
}
/**
- * Returns the value of this {@code AtomicLong} as a {@code double}
- * after a widening primitive conversion.
+ * Returns the current value of this {@code AtomicLong} as a {@code double}
+ * after a widening primitive conversion,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
}
+ // jdk9
+
+ /**
+ * Returns the current value, with memory semantics of reading as if the
+ * variable was declared non-{@code volatile}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final long getPlain() {
+ return (long)VALUE.get(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue}, with memory semantics
+ * of setting as if the variable was declared non-{@code volatile}
+ * and non-{@code final}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(long newValue) {
+ VALUE.set(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final long getOpaque() {
+ return (long)VALUE.getOpaque(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(long newValue) {
+ VALUE.setOpaque(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final long getAcquire() {
+ return (long)VALUE.getAcquire(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(long newValue) {
+ VALUE.setRelease(this, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchange(long expectedValue, long newValue) {
+ return (long)VALUE.compareAndExchange(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
+ return (long)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchangeRelease(long expectedValue, long newValue) {
+ return (long)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
+ return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
+ return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
+ return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongArray.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongArray.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,43 +35,24 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
/**
* A {@code long} array in which elements may be updated atomically.
- * See the {@link java.util.concurrent.atomic} package specification
- * for description of the properties of atomic variables.
+ * See the {@link VarHandle} specification for descriptions of the
+ * properties of atomic accesses.
* @since 1.5
* @author Doug Lea
*/
public class AtomicLongArray implements java.io.Serializable {
private static final long serialVersionUID = -2308431214976778248L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final VarHandle AA
+ = MethodHandles.arrayElementVarHandle(long[].class);
private final long[] array;
- static {
- ABASE = U.arrayBaseOffset(long[].class);
- int scale = U.arrayIndexScale(long[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- }
-
- private long checkedByteOffset(int i) {
- if (i < 0 || i >= array.length)
- throw new IndexOutOfBoundsException("index " + i);
-
- return byteOffset(i);
- }
-
- private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
- }
-
/**
* Creates a new AtomicLongArray of the given length, with all
* elements initially zero.
@@ -104,147 +85,155 @@
}
/**
- * Gets the current value at position {@code i}.
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
public final long get(int i) {
- return getRaw(checkedByteOffset(i));
- }
-
- private long getRaw(long offset) {
- return U.getLongVolatile(array, offset);
+ return (long)AA.getVolatile(array, i);
}
/**
- * Sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, long newValue) {
- U.putLongVolatile(array, checkedByteOffset(i), newValue);
+ AA.setVolatile(array, i, newValue);
}
/**
- * Eventually sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, long newValue) {
- U.putLongRelease(array, checkedByteOffset(i), newValue);
+ AA.setRelease(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given value
- * and returns the old value.
+ * Atomically sets the element at index {@code i} to {@code
+ * newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(int i, long newValue) {
- return U.getAndSetLong(array, checkedByteOffset(i), newValue);
+ return (long)AA.getAndSet(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(int i, long expect, long update) {
- return compareAndSetRaw(checkedByteOffset(i), expect, update);
- }
-
- private boolean compareAndSetRaw(long offset, long expect, long update) {
- return U.compareAndSwapLong(array, offset, expect, update);
+ public final boolean compareAndSet(int i, long expectedValue, long newValue) {
+ return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
- *
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public final boolean weakCompareAndSet(int i, long expect, long update) {
- return compareAndSet(i, expect, update);
+ public final boolean weakCompareAndSet(int i, long expectedValue, long newValue) {
+ return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
- * Atomically increments by one the element at index {@code i}.
+ * Atomically increments the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(i, 1)}.
*
* @param i the index
* @return the previous value
*/
public final long getAndIncrement(int i) {
- return getAndAdd(i, 1);
+ return (long)AA.getAndAdd(array, i, 1L);
}
/**
- * Atomically decrements by one the element at index {@code i}.
+ * Atomically decrements the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
+ *
+ * <p>Equivalent to {@code getAndAdd(i, -1)}.
*
* @param i the index
* @return the previous value
*/
public final long getAndDecrement(int i) {
- return getAndAdd(i, -1);
+ return (long)AA.getAndAdd(array, i, -1L);
}
/**
- * Atomically adds the given value to the element at index {@code i}.
+ * Atomically adds the given value to the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param i the index
* @param delta the value to add
* @return the previous value
*/
public final long getAndAdd(int i, long delta) {
- return U.getAndAddLong(array, checkedByteOffset(i), delta);
+ return (long)AA.getAndAdd(array, i, delta);
}
/**
- * Atomically increments by one the element at index {@code i}.
+ * Atomically increments the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(i, 1)}.
*
* @param i the index
* @return the updated value
*/
public final long incrementAndGet(int i) {
- return getAndAdd(i, 1) + 1;
+ return (long)AA.addAndGet(array, i, 1L);
}
/**
- * Atomically decrements by one the element at index {@code i}.
+ * Atomically decrements the value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
+ *
+ * <p>Equivalent to {@code addAndGet(i, -1)}.
*
* @param i the index
* @return the updated value
*/
public final long decrementAndGet(int i) {
- return getAndAdd(i, -1) - 1;
+ return (long)AA.addAndGet(array, i, -1L);
}
/**
- * Atomically adds the given value to the element at index {@code i}.
+ * Atomically adds the given value to the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param i the index
* @param delta the value to add
* @return the updated value
*/
public long addAndGet(int i, long delta) {
- return getAndAdd(i, delta) + delta;
+ return (long)AA.addAndGet(array, i, delta);
}
/**
@@ -259,13 +248,14 @@
* @since 1.8
*/
public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ long prev = get(i), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsLong(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -280,23 +270,25 @@
* @since 1.8
*/
public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.applyAsLong(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ long prev = get(i), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.applyAsLong(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the previous value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the previous value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -306,23 +298,25 @@
*/
public final long getAndAccumulate(int i, long x,
LongBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ long prev = get(i), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsLong(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the updated value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the updated value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -332,13 +326,14 @@
*/
public final long accumulateAndGet(int i, long x,
LongBinaryOperator accumulatorFunction) {
- long offset = checkedByteOffset(i);
- long prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.applyAsLong(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ long prev = get(i), next = 0L;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.applyAsLong(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -353,11 +348,189 @@
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
- b.append(getRaw(byteOffset(i)));
+ b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}
+ // jdk9
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory semantics of reading as if the variable was declared
+ * non-{@code volatile}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final long getPlain(int i) {
+ return (long)AA.get(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory semantics of setting as if the variable was
+ * declared non-{@code volatile} and non-{@code final}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(int i, long newValue) {
+ AA.set(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final long getOpaque(int i) {
+ return (long)AA.getOpaque(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(int i, long newValue) {
+ AA.setOpaque(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final long getAcquire(int i) {
+ return (long)AA.getAcquire(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(int i, long newValue) {
+ AA.setRelease(array, i, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchange(int i, long expectedValue, long newValue) {
+ return (long)AA.compareAndExchange(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchangeAcquire(int i, long expectedValue, long newValue) {
+ return (long)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final long compareAndExchangeRelease(int i, long expectedValue, long newValue) {
+ return (long)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(int i, long expectedValue, long newValue) {
+ return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(int i, long expectedValue, long newValue) {
+ return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(int i, long expectedValue, long newValue) {
+ return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Fri Jul 15 14:04:09 2016 -0700
@@ -42,6 +42,7 @@
import java.security.PrivilegedExceptionAction;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
+import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@@ -153,8 +154,8 @@
public abstract void lazySet(T obj, long newValue);
/**
- * Gets the current value held in the field of the given object managed
- * by this updater.
+ * Returns the current value held in the field of the given object
+ * managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@@ -366,7 +367,7 @@
}
private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
@@ -497,7 +498,7 @@
}
private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* An {@code AtomicMarkableReference} maintains an object reference
* along with a mark bit, that can be updated atomically.
@@ -188,20 +191,19 @@
casPair(current, Pair.of(expectedReference, newMark)));
}
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long PAIR;
+ // VarHandle mechanics
+ private static final VarHandle PAIR;
static {
try {
- PAIR = U.objectFieldOffset
- (AtomicMarkableReference.class.getDeclaredField("pair"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
+ Pair.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return PAIR.compareAndSet(this, cmp, val);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,33 +35,32 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
/**
- * An object reference that may be updated atomically. See the {@link
- * java.util.concurrent.atomic} package specification for description
- * of the properties of atomic variables.
+ * An object reference that may be updated atomically. See the {@link
+ * VarHandle} specification for descriptions of the properties of
+ * atomic accesses.
* @since 1.5
* @author Doug Lea
* @param <V> The type of object referred to by this reference
*/
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
-
+ private static final VarHandle VALUE;
static {
try {
- VALUE = U.objectFieldOffset
- (AtomicReference.class.getDeclaredField("value"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
- private volatile V value;
+ private volatile Object value;
/**
* Creates a new AtomicReference with the given initial value.
@@ -79,16 +78,19 @@
}
/**
- * Gets the current value.
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
+ @SuppressWarnings("unchecked")
public final V get() {
- return value;
+ return (V)value;
}
/**
- * Sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@@ -97,52 +99,53 @@
}
/**
- * Eventually sets to the given value.
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(V newValue) {
- U.putObjectRelease(this, VALUE, newValue);
- }
-
- /**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- * @param expect the expected value
- * @param update the new value
- * @return {@code true} if successful. False return indicates that
- * the actual value was not equal to the expected value.
- */
- public final boolean compareAndSet(V expect, V update) {
- return U.compareAndSwapObject(this, VALUE, expect, update);
+ VALUE.setRelease(this, newValue);
}
/**
- * Atomically sets the value to the given updated value
- * if the current value {@code ==} the expected value.
- *
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
+ * Atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
- * @param expect the expected value
- * @param update the new value
- * @return {@code true} if successful
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful. False return indicates that
+ * the actual value was not equal to the expected value.
*/
- public final boolean weakCompareAndSet(V expect, V update) {
- return U.compareAndSwapObject(this, VALUE, expect, update);
+ public final boolean compareAndSet(V expectedValue, V newValue) {
+ return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
- * Atomically sets to the given value and returns the old value.
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ */
+ public final boolean weakCompareAndSet(V expectedValue, V newValue) {
+ return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
- return (V)U.getAndSetObject(this, VALUE, newValue);
+ return (V)VALUE.getAndSet(this, newValue);
}
/**
@@ -156,12 +159,14 @@
* @since 1.8
*/
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get();
- next = updateFunction.apply(prev);
- } while (!compareAndSet(prev, next));
- return prev;
+ V prev = get(), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.apply(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -175,12 +180,14 @@
* @since 1.8
*/
public final V updateAndGet(UnaryOperator<V> updateFunction) {
- V prev, next;
- do {
- prev = get();
- next = updateFunction.apply(prev);
- } while (!compareAndSet(prev, next));
- return next;
+ V prev = get(), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.apply(prev);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -199,12 +206,14 @@
*/
public final V getAndAccumulate(V x,
BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get();
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(prev, next));
- return prev;
+ V prev = get(), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.apply(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return prev;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -223,12 +232,14 @@
*/
public final V accumulateAndGet(V x,
BinaryOperator<V> accumulatorFunction) {
- V prev, next;
- do {
- prev = get();
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSet(prev, next));
- return next;
+ V prev = get(), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.apply(prev, x);
+ if (weakCompareAndSetVolatile(prev, next))
+ return next;
+ haveNext = (prev == (prev = get()));
+ }
}
/**
@@ -239,4 +250,166 @@
return String.valueOf(get());
}
+ // jdk9
+
+ /**
+ * Returns the current value, with memory semantics of reading as
+ * if the variable was declared non-{@code volatile}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final V getPlain() {
+ return (V)VALUE.get(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue}, with memory semantics
+ * of setting as if the variable was declared non-{@code volatile}
+ * and non-{@code final}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(V newValue) {
+ VALUE.set(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final V getOpaque() {
+ return (V)VALUE.getOpaque(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(V newValue) {
+ VALUE.setOpaque(this, newValue);
+ }
+
+ /**
+ * Returns the current value,
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @return the value
+ * @since 9
+ */
+ public final V getAcquire() {
+ return (V)VALUE.getAcquire(this);
+ }
+
+ /**
+ * Sets the value to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(V newValue) {
+ VALUE.setRelease(this, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final V compareAndExchange(V expectedValue, V newValue) {
+ return (V)VALUE.compareAndExchange(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final V compareAndExchangeAcquire(V expectedValue, V newValue) {
+ return (V)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the value to {@code newValue} if the current value,
+ * referred to as the <em>witness value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final V compareAndExchangeRelease(V expectedValue, V newValue) {
+ return (V)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) {
+ return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(V expectedValue, V newValue) {
+ return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the value to {@code newValue}
+ * if the current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(V expectedValue, V newValue) {
+ return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+ }
+
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,54 +35,28 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.lang.reflect.Array;
+import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
/**
* An array of object references in which elements may be updated
- * atomically. See the {@link java.util.concurrent.atomic} package
- * specification for description of the properties of atomic
- * variables.
+ * atomically. See the {@link VarHandle} specification for
+ * descriptions of the properties of atomic accesses.
* @since 1.5
* @author Doug Lea
* @param <E> The base class of elements held in this array
*/
public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final long serialVersionUID = -6209656149925076980L;
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long ARRAY;
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final VarHandle AA
+ = MethodHandles.arrayElementVarHandle(Object[].class);
private final Object[] array; // must have exact type Object[]
- static {
- try {
- ARRAY = U.objectFieldOffset
- (AtomicReferenceArray.class.getDeclaredField("array"));
- ABASE = U.arrayBaseOffset(Object[].class);
- int scale = U.arrayIndexScale(Object[].class);
- if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
- ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
- private long checkedByteOffset(int i) {
- if (i < 0 || i >= array.length)
- throw new IndexOutOfBoundsException("index " + i);
-
- return byteOffset(i);
- }
-
- private static long byteOffset(int i) {
- return ((long) i << ASHIFT) + ABASE;
- }
-
/**
* Creates a new AtomicReferenceArray of the given length, with all
* elements initially null.
@@ -115,44 +89,44 @@
}
/**
- * Gets the current value at position {@code i}.
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
+ @SuppressWarnings("unchecked")
public final E get(int i) {
- return getRaw(checkedByteOffset(i));
- }
-
- @SuppressWarnings("unchecked")
- private E getRaw(long offset) {
- return (E) U.getObjectVolatile(array, offset);
+ return (E)AA.getVolatile(array, i);
}
/**
- * Sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, E newValue) {
- U.putObjectVolatile(array, checkedByteOffset(i), newValue);
+ AA.setVolatile(array, i, newValue);
}
/**
- * Eventually sets the element at position {@code i} to the given value.
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, E newValue) {
- U.putObjectRelease(array, checkedByteOffset(i), newValue);
+ AA.setRelease(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * value and returns the old value.
+ * Atomically sets the element at index {@code i} to {@code
+ * newValue} and returns the old value,
+ * with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
@@ -160,42 +134,36 @@
*/
@SuppressWarnings("unchecked")
public final E getAndSet(int i, E newValue) {
- return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
+ return (E)AA.getAndSet(array, i, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
- public final boolean compareAndSet(int i, E expect, E update) {
- return compareAndSetRaw(checkedByteOffset(i), expect, update);
- }
-
- private boolean compareAndSetRaw(long offset, E expect, E update) {
- return U.compareAndSwapObject(array, offset, expect, update);
+ public final boolean compareAndSet(int i, E expectedValue, E newValue) {
+ return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
- * Atomically sets the element at position {@code i} to the given
- * updated value if the current value {@code ==} the expected value.
- *
- * <p><a href="package-summary.html#weakCompareAndSet">May fail
- * spuriously and does not provide ordering guarantees</a>, so is
- * only rarely an appropriate alternative to {@code compareAndSet}.
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
- * @param expect the expected value
- * @param update the new value
+ * @param expectedValue the expected value
+ * @param newValue the new value
* @return {@code true} if successful
*/
- public final boolean weakCompareAndSet(int i, E expect, E update) {
- return compareAndSet(i, expect, update);
+ public final boolean weakCompareAndSet(int i, E expectedValue, E newValue) {
+ return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
@@ -210,13 +178,14 @@
* @since 1.8
*/
public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.apply(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ E prev = get(i), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.apply(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -231,23 +200,25 @@
* @since 1.8
*/
public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = updateFunction.apply(prev);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ E prev = get(i), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = updateFunction.apply(prev);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the previous value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the previous value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -257,23 +228,25 @@
*/
public final E getAndAccumulate(int i, E x,
BinaryOperator<E> accumulatorFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return prev;
+ E prev = get(i), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.apply(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return prev;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
* Atomically updates the element at index {@code i} with the
- * results of applying the given function to the current and
- * given values, returning the updated value. The function should
- * be side-effect-free, since it may be re-applied when attempted
+ * results of applying the given function to the current and given
+ * values, returning the updated value. The function should be
+ * side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
- * applied with the current value at index {@code i} as its first
- * argument, and the given update as the second argument.
+ * applied with the current value of the element at index {@code i}
+ * as its first argument, and the given update as the second
+ * argument.
*
* @param i the index
* @param x the update value
@@ -283,13 +256,14 @@
*/
public final E accumulateAndGet(int i, E x,
BinaryOperator<E> accumulatorFunction) {
- long offset = checkedByteOffset(i);
- E prev, next;
- do {
- prev = getRaw(offset);
- next = accumulatorFunction.apply(prev, x);
- } while (!compareAndSetRaw(offset, prev, next));
- return next;
+ E prev = get(i), next = null;
+ for (boolean haveNext = false;;) {
+ if (!haveNext)
+ next = accumulatorFunction.apply(prev, x);
+ if (weakCompareAndSetVolatile(i, prev, next))
+ return next;
+ haveNext = (prev == (prev = get(i)));
+ }
}
/**
@@ -304,7 +278,7 @@
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
- b.append(getRaw(byteOffset(i)));
+ b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
@@ -326,7 +300,199 @@
throw new java.io.InvalidObjectException("Not array type");
if (a.getClass() != Object[].class)
a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
- U.putObjectVolatile(this, ARRAY, a);
+ Field arrayField = java.security.AccessController.doPrivileged(
+ (java.security.PrivilegedAction<Field>) () -> {
+ try {
+ Field f = AtomicReferenceArray.class
+ .getDeclaredField("array");
+ f.setAccessible(true);
+ return f;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }});
+ try {
+ arrayField.set(this, a);
+ } catch (IllegalAccessException e) {
+ throw new Error(e);
+ }
+ }
+
+ // jdk9
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory semantics of reading as if the variable was declared
+ * non-{@code volatile}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final E getPlain(int i) {
+ return (E)AA.get(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory semantics of setting as if the variable was
+ * declared non-{@code volatile} and non-{@code final}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setPlain(int i, E newValue) {
+ AA.set(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getOpaque}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final E getOpaque(int i) {
+ return (E)AA.getOpaque(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setOpaque}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setOpaque(int i, E newValue) {
+ AA.setOpaque(array, i, newValue);
+ }
+
+ /**
+ * Returns the current value of the element at index {@code i},
+ * with memory effects as specified by {@link VarHandle#getAcquire}.
+ *
+ * @param i the index
+ * @return the value
+ * @since 9
+ */
+ public final E getAcquire(int i) {
+ return (E)AA.getAcquire(array, i);
+ }
+
+ /**
+ * Sets the element at index {@code i} to {@code newValue},
+ * with memory effects as specified by {@link VarHandle#setRelease}.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @since 9
+ */
+ public final void setRelease(int i, E newValue) {
+ AA.setRelease(array, i, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchange}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final E compareAndExchange(int i, E expectedValue, E newValue) {
+ return (E)AA.compareAndExchange(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final E compareAndExchangeAcquire(int i, E expectedValue, E newValue) {
+ return (E)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Atomically sets the element at index {@code i} to {@code newValue}
+ * if the element's current value, referred to as the <em>witness
+ * value</em>, {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#compareAndExchangeRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return the witness value, which will be the same as the
+ * expected value if successful
+ * @since 9
+ */
+ public final E compareAndExchangeRelease(int i, E expectedValue, E newValue) {
+ return (E)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetVolatile}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetVolatile(int i, E expectedValue, E newValue) {
+ return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetAcquire}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue) {
+ return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
+ }
+
+ /**
+ * Possibly atomically sets the element at index {@code i} to
+ * {@code newValue} if the element's current value {@code == expectedValue},
+ * with memory effects as specified by
+ * {@link VarHandle#weakCompareAndSetRelease}.
+ *
+ * @param i the index
+ * @param expectedValue the expected value
+ * @param newValue the new value
+ * @return {@code true} if successful
+ * @since 9
+ */
+ public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) {
+ return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Fri Jul 15 14:04:09 2016 -0700
@@ -42,6 +42,7 @@
import java.security.PrivilegedExceptionAction;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@@ -168,8 +169,8 @@
public abstract void lazySet(T obj, V newValue);
/**
- * Gets the current value held in the field of the given object managed
- * by this updater.
+ * Returns the current value held in the field of the given object
+ * managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@@ -284,7 +285,7 @@
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
/**
* An {@code AtomicStampedReference} maintains an object reference
* along with an integer "stamp", that can be updated atomically.
@@ -188,20 +191,19 @@
casPair(current, Pair.of(expectedReference, newStamp)));
}
- // Unsafe mechanics
-
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long PAIR;
+ // VarHandle mechanics
+ private static final VarHandle PAIR;
static {
try {
- PAIR = U.objectFieldOffset
- (AtomicStampedReference.class.getDeclaredField("pair"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
+ Pair.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
- return U.compareAndSwapObject(this, PAIR, cmp, val);
+ return PAIR.compareAndSet(this, cmp, val);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/LongAccumulator.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/LongAccumulator.java Fri Jul 15 14:04:09 2016 -0700
@@ -68,7 +68,7 @@
* <p>Class {@link LongAdder} provides analogs of the functionality of
* this class for the common special case of maintaining counts and
* sums. The call {@code new LongAdder()} is equivalent to {@code new
- * LongAccumulator((x, y) -> x + y, 0L}.
+ * LongAccumulator((x, y) -> x + y, 0L)}.
*
* <p>This class extends {@link Number}, but does <em>not</em> define
* methods such as {@code equals}, {@code hashCode} and {@code
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,10 +35,13 @@
package java.util.concurrent.atomic;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleBinaryOperator;
import java.util.function.LongBinaryOperator;
+import jdk.internal.misc.Unsafe;
/**
* A package-local class holding common representation and mechanics
@@ -123,22 +126,21 @@
volatile long value;
Cell(long x) { value = x; }
final boolean cas(long cmp, long val) {
- return U.compareAndSwapLong(this, VALUE, cmp, val);
+ return VALUE.compareAndSet(this, cmp, val);
}
final void reset() {
- U.putLongVolatile(this, VALUE, 0L);
+ VALUE.setVolatile(this, 0L);
}
final void reset(long identity) {
- U.putLongVolatile(this, VALUE, identity);
+ VALUE.setVolatile(this, identity);
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long VALUE;
+ // VarHandle mechanics
+ private static final VarHandle VALUE;
static {
try {
- VALUE = U.objectFieldOffset
- (Cell.class.getDeclaredField("value"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ VALUE = l.findVarHandle(Cell.class, "value", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -174,14 +176,14 @@
* CASes the base field.
*/
final boolean casBase(long cmp, long val) {
- return U.compareAndSwapLong(this, BASE, cmp, val);
+ return BASE.compareAndSet(this, cmp, val);
}
/**
* CASes the cellsBusy field from 0 to 1 to acquire lock.
*/
final boolean casCellsBusy() {
- return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
+ return CELLSBUSY.compareAndSet(this, 0, 1);
}
/**
@@ -371,18 +373,16 @@
}
}
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long BASE;
- private static final long CELLSBUSY;
+ // Unsafe and VarHandle mechanics
+ private static final Unsafe U = Unsafe.getUnsafe();
+ private static final VarHandle BASE;
+ private static final VarHandle CELLSBUSY;
private static final long PROBE;
static {
try {
- BASE = U.objectFieldOffset
- (Striped64.class.getDeclaredField("base"));
- CELLSBUSY = U.objectFieldOffset
- (Striped64.class.getDeclaredField("cellsBusy"));
-
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ BASE = l.findVarHandle(Striped64.class, "base", long.class);
+ CELLSBUSY = l.findVarHandle(Striped64.class, "cellsBusy", int.class);
PROBE = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomProbe"));
} catch (ReflectiveOperationException e) {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,26 +35,10 @@
/**
* A small toolkit of classes that support lock-free thread-safe
- * programming on single variables. In essence, the classes in this
- * package extend the notion of {@code volatile} values, fields, and
- * array elements to those that also provide an atomic conditional update
- * operation of the form:
- *
- * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
- *
- * <p>This method (which varies in argument types across different
- * classes) atomically sets a variable to the {@code updateValue} if it
- * currently holds the {@code expectedValue}, reporting {@code true} on
- * success. The classes in this package also contain methods to get and
- * unconditionally set values, as well as a weaker conditional atomic
- * update operation {@code weakCompareAndSet} described below.
- *
- * <p>The specifications of these methods enable implementations to
- * employ efficient machine-level atomic instructions that are available
- * on contemporary processors. However on some platforms, support may
- * entail some form of internal locking. Thus the methods are not
- * strictly guaranteed to be non-blocking --
- * a thread may block transiently before performing the operation.
+ * programming on single variables. Instances of Atomic classes
+ * maintain values that are accessed and updated using methods
+ * otherwise available for fields using associated atomic {@link
+ * java.lang.invoke.VarHandle} operations.
*
* <p>Instances of classes
* {@link java.util.concurrent.atomic.AtomicBoolean},
@@ -92,45 +76,26 @@
* return prev; // return next; for transformAndGet
* }}</pre>
*
- * <p>The memory effects for accesses and updates of atomics generally
- * follow the rules for volatiles, as stated in
- * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
- * Chapter 17 of
- * <cite>The Java™ Language Specification</cite></a>:
- *
- * <ul>
- *
- * <li>{@code get} has the memory effects of reading a
- * {@code volatile} variable.
- *
- * <li>{@code set} has the memory effects of writing (assigning) a
- * {@code volatile} variable.
+ * <p>These classes are not general purpose replacements for {@code
+ * java.lang.Integer} and related classes. They do <em>not</em>
+ * define methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo}. Because atomic variables are expected to be mutated,
+ * they are poor choices for hash table keys.
*
- * <li>{@code lazySet} has the memory effects of writing (assigning)
- * a {@code volatile} variable except that it permits reorderings with
- * subsequent (but not previous) memory actions that do not themselves
- * impose reordering constraints with ordinary non-{@code volatile}
- * writes. Among other usage contexts, {@code lazySet} may apply when
- * nulling out, for the sake of garbage collection, a reference that is
- * never accessed again.
+ * <p>The
+ * {@link java.util.concurrent.atomic.AtomicIntegerArray},
+ * {@link java.util.concurrent.atomic.AtomicLongArray}, and
+ * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
+ * further extend atomic operation support to arrays of these types.
+ * These classes are also notable in providing {@code volatile} access
+ * semantics for their array elements.
*
- * <li>{@code weakCompareAndSet} atomically reads and conditionally
- * writes a variable but does <em>not</em>
- * create any happens-before orderings, so provides no guarantees
- * with respect to previous or subsequent reads and writes of any
- * variables other than the target of the {@code weakCompareAndSet}.
- *
- * <li>{@code compareAndSet}
- * and all other read-and-update operations such as {@code getAndIncrement}
- * have the memory effects of both reading and
- * writing {@code volatile} variables.
- * </ul>
- *
- * <p>In addition to classes representing single values, this package
- * contains <em>Updater</em> classes that can be used to obtain
- * {@code compareAndSet} operations on any selected {@code volatile}
- * field of any selected class.
- *
+ * <p>In addition to classes representing single values and arrays,
+ * this package contains <em>Updater</em> classes that can be used to
+ * obtain {@code compareAndSet} and related operations on any selected
+ * {@code volatile} field of any selected class. These classes
+ * predate the introduction of {@link
+ * java.lang.invoke.VarHandle}, and are of more limited use.
* {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
* {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
* {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
@@ -143,38 +108,6 @@
* reflection-based setup, less convenient usage, and weaker
* guarantees.
*
- * <p>The
- * {@link java.util.concurrent.atomic.AtomicIntegerArray},
- * {@link java.util.concurrent.atomic.AtomicLongArray}, and
- * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
- * further extend atomic operation support to arrays of these types.
- * These classes are also notable in providing {@code volatile} access
- * semantics for their array elements, which is not supported for
- * ordinary arrays.
- *
- * <p id="weakCompareAndSet">The atomic classes also support method
- * {@code weakCompareAndSet}, which has limited applicability. On some
- * platforms, the weak version may be more efficient than {@code
- * compareAndSet} in the normal case, but differs in that any given
- * invocation of the {@code weakCompareAndSet} method may return {@code
- * false} <em>spuriously</em> (that is, for no apparent reason). A
- * {@code false} return means only that the operation may be retried if
- * desired, relying on the guarantee that repeated invocation when the
- * variable holds {@code expectedValue} and no other thread is also
- * attempting to set the variable will eventually succeed. (Such
- * spurious failures may for example be due to memory contention effects
- * that are unrelated to whether the expected and current values are
- * equal.) Additionally {@code weakCompareAndSet} does not provide
- * ordering guarantees that are usually needed for synchronization
- * control. However, the method may be useful for updating counters and
- * statistics when such updates are unrelated to the other
- * happens-before orderings of a program. When a thread sees an update
- * to an atomic variable caused by a {@code weakCompareAndSet}, it does
- * not necessarily see updates to any <em>other</em> variables that
- * occurred before the {@code weakCompareAndSet}. This may be
- * acceptable when, for example, updating performance statistics, but
- * rarely otherwise.
- *
* <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
* class associates a single boolean with a reference. For example, this
* bit might be used inside a data structure to mean that the object
@@ -185,29 +118,6 @@
* used for example, to represent version numbers corresponding to
* series of updates.
*
- * <p>Atomic classes are designed primarily as building blocks for
- * implementing non-blocking data structures and related infrastructure
- * classes. The {@code compareAndSet} method is not a general
- * replacement for locking. It applies only when critical updates for an
- * object are confined to a <em>single</em> variable.
- *
- * <p>Atomic classes are not general purpose replacements for
- * {@code java.lang.Integer} and related classes. They do <em>not</em>
- * define methods such as {@code equals}, {@code hashCode} and
- * {@code compareTo}. (Because atomic variables are expected to be
- * mutated, they are poor choices for hash table keys.) Additionally,
- * classes are provided only for those types that are commonly useful in
- * intended applications. For example, there is no atomic class for
- * representing {@code byte}. In those infrequent cases where you would
- * like to do so, you can use an {@code AtomicInteger} to hold
- * {@code byte} values, and cast appropriately.
- *
- * You can also hold floats using
- * {@link java.lang.Float#floatToRawIntBits} and
- * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
- * {@link java.lang.Double#doubleToRawLongBits} and
- * {@link java.lang.Double#longBitsToDouble} conversions.
- *
* @since 1.5
*/
package java.util.concurrent.atomic;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,6 +35,8 @@
package java.util.concurrent.locks;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@@ -113,7 +115,7 @@
protected final void setState(long newState) {
// Use putLongVolatile instead of ordinary volatile store when
// using compareAndSwapLong, for sake of some 32bit systems.
- U.putLongVolatile(this, STATE, newState);
+ STATE.setVolatile(this, newState);
}
/**
@@ -128,7 +130,7 @@
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(long expect, long update) {
- return U.compareAndSwapLong(this, STATE, expect, update);
+ return STATE.compareAndSet(this, expect, update);
}
// Queuing utilities
@@ -149,7 +151,7 @@
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
+ node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return oldTail;
@@ -172,7 +174,7 @@
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
+ node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
@@ -1810,28 +1812,17 @@
}
}
- /**
- * Setup to support compareAndSet. We need to natively implement
- * this here: For the sake of permitting future enhancements, we
- * cannot explicitly subclass AtomicLong, which would be
- * efficient and useful otherwise. So, as the lesser of evils, we
- * natively implement using hotspot intrinsics API. And while we
- * are at it, we do the same for other CASable fields (which could
- * otherwise be done with atomic field updaters).
- */
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long HEAD;
- private static final long TAIL;
+ // VarHandle mechanics
+ private static final VarHandle STATE;
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
static {
try {
- STATE = U.objectFieldOffset
- (AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
- HEAD = U.objectFieldOffset
- (AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
+ HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
+ TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -1846,7 +1837,7 @@
*/
private final void initializeSyncQueue() {
Node h;
- if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+ if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
@@ -1854,6 +1845,6 @@
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
- return U.compareAndSwapObject(this, TAIL, expect, update);
+ return TAIL.compareAndSet(this, expect, update);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,11 +35,12 @@
package java.util.concurrent.locks;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;
-import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* Provides a framework for implementing blocking locks and related
@@ -506,40 +507,41 @@
/** Constructor used by addWaiter. */
Node(Node nextWaiter) {
this.nextWaiter = nextWaiter;
- U.putObject(this, THREAD, Thread.currentThread());
+ THREAD.set(this, Thread.currentThread());
}
/** Constructor used by addConditionWaiter. */
Node(int waitStatus) {
- U.putInt(this, WAITSTATUS, waitStatus);
- U.putObject(this, THREAD, Thread.currentThread());
+ WAITSTATUS.set(this, waitStatus);
+ THREAD.set(this, Thread.currentThread());
}
/** CASes waitStatus field. */
final boolean compareAndSetWaitStatus(int expect, int update) {
- return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
+ return WAITSTATUS.compareAndSet(this, expect, update);
}
/** CASes next field. */
final boolean compareAndSetNext(Node expect, Node update) {
- return U.compareAndSwapObject(this, NEXT, expect, update);
+ return NEXT.compareAndSet(this, expect, update);
+ }
+
+ final void setPrevRelaxed(Node p) {
+ PREV.set(this, p);
}
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long NEXT;
- static final long PREV;
- private static final long THREAD;
- private static final long WAITSTATUS;
+ // VarHandle mechanics
+ private static final VarHandle NEXT;
+ private static final VarHandle PREV;
+ private static final VarHandle THREAD;
+ private static final VarHandle WAITSTATUS;
static {
try {
- NEXT = U.objectFieldOffset
- (Node.class.getDeclaredField("next"));
- PREV = U.objectFieldOffset
- (Node.class.getDeclaredField("prev"));
- THREAD = U.objectFieldOffset
- (Node.class.getDeclaredField("thread"));
- WAITSTATUS = U.objectFieldOffset
- (Node.class.getDeclaredField("waitStatus"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ PREV = l.findVarHandle(Node.class, "prev", Node.class);
+ THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
+ WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -595,7 +597,7 @@
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
- return U.compareAndSwapInt(this, STATE, expect, update);
+ return STATE.compareAndSet(this, expect, update);
}
// Queuing utilities
@@ -616,7 +618,7 @@
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
+ node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return oldTail;
@@ -639,7 +641,7 @@
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
- U.putObject(node, Node.PREV, oldTail);
+ node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
@@ -887,7 +889,6 @@
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
- @ReservedStackAccess
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
@@ -1220,7 +1221,6 @@
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
- @ReservedStackAccess
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@@ -1284,7 +1284,6 @@
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
- @ReservedStackAccess
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
@@ -1365,7 +1364,6 @@
* and can represent anything you like.
* @return the value returned from {@link #tryReleaseShared}
*/
- @ReservedStackAccess
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
@@ -2279,28 +2277,17 @@
}
}
- /**
- * Setup to support compareAndSet. We need to natively implement
- * this here: For the sake of permitting future enhancements, we
- * cannot explicitly subclass AtomicInteger, which would be
- * efficient and useful otherwise. So, as the lesser of evils, we
- * natively implement using hotspot intrinsics API. And while we
- * are at it, we do the same for other CASable fields (which could
- * otherwise be done with atomic field updaters).
- */
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long STATE;
- private static final long HEAD;
- private static final long TAIL;
+ // VarHandle mechanics
+ private static final VarHandle STATE;
+ private static final VarHandle HEAD;
+ private static final VarHandle TAIL;
static {
try {
- STATE = U.objectFieldOffset
- (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
- HEAD = U.objectFieldOffset
- (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
- TAIL = U.objectFieldOffset
- (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
+ MethodHandles.Lookup l = MethodHandles.lookup();
+ STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
+ HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
+ TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -2315,7 +2302,7 @@
*/
private final void initializeSyncQueue() {
Node h;
- if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+ if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
@@ -2323,6 +2310,6 @@
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
- return U.compareAndSwapObject(this, TAIL, expect, update);
+ return TAIL.compareAndSet(this, expect, update);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Fri Jul 15 14:04:09 2016 -0700
@@ -396,7 +396,6 @@
* re-acquire the lock associated with this condition. When the
* thread returns it is <em>guaranteed</em> to hold this lock.
*
- *
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
@@ -408,7 +407,6 @@
* case, whether or not the test for interruption occurs before the lock
* is released.
*
- *
* <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows:
* <pre> {@code
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java Fri Jul 15 14:04:09 2016 -0700
@@ -35,6 +35,8 @@
package java.util.concurrent.locks;
+import jdk.internal.misc.Unsafe;
+
/**
* Basic thread blocking primitives for creating locks and other
* synchronization classes.
@@ -405,16 +407,30 @@
return r;
}
+ /**
+ * Returns the thread id for the given thread. We must access
+ * this directly rather than via method Thread.getId() because
+ * getId() is not final, and has been known to be overridden in
+ * ways that do not preserve unique mappings.
+ */
+ static final long getThreadId(Thread thread) {
+ return U.getLongVolatile(thread, TID);
+ }
+
// Hotspot implementation via intrinsics API
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final Unsafe U = Unsafe.getUnsafe();
private static final long PARKBLOCKER;
private static final long SECONDARY;
+ private static final long TID;
static {
try {
PARKBLOCKER = U.objectFieldOffset
(Thread.class.getDeclaredField("parkBlocker"));
SECONDARY = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+ TID = U.objectFieldOffset
+ (Thread.class.getDeclaredField("tid"));
+
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReadWriteLock.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReadWriteLock.java Fri Jul 15 14:04:09 2016 -0700
@@ -79,7 +79,6 @@
* and measurement will establish whether the use of a read-write lock is
* suitable for your application.
*
- *
* <p>Although the basic operation of a read-write lock is straight-forward,
* there are many policy decisions that an implementation must make, which
* may affect the effectiveness of the read-write lock in a given application.
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java Fri Jul 15 14:04:09 2016 -0700
@@ -119,12 +119,6 @@
private static final long serialVersionUID = -5179523762034025860L;
/**
- * Performs {@link Lock#lock}. The main reason for subclassing
- * is to allow fast path for nonfair version.
- */
- abstract void lock();
-
- /**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@@ -201,19 +195,6 @@
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
-
- /**
- * Performs lock. Try immediate barge, backing up to normal
- * acquire on failure.
- */
- @ReservedStackAccess
- final void lock() {
- if (compareAndSetState(0, 1))
- setExclusiveOwnerThread(Thread.currentThread());
- else
- acquire(1);
- }
-
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
@@ -224,11 +205,6 @@
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
-
- final void lock() {
- acquire(1);
- }
-
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
@@ -288,7 +264,7 @@
* at which time the lock hold count is set to one.
*/
public void lock() {
- sync.lock();
+ sync.acquire(1);
}
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java Fri Jul 15 14:04:09 2016 -0700
@@ -37,6 +37,7 @@
import java.util.Collection;
import java.util.concurrent.TimeUnit;
+import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* An implementation of {@link ReadWriteLock} supporting similar
@@ -278,7 +279,7 @@
static final class HoldCounter {
int count; // initially 0
// Use id, not reference, to avoid garbage retention
- final long tid = getThreadId(Thread.currentThread());
+ final long tid = LockSupport.getThreadId(Thread.currentThread());
}
/**
@@ -367,7 +368,7 @@
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/
-
+ @ReservedStackAccess
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
@@ -379,6 +380,7 @@
return free;
}
+ @ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
@@ -411,6 +413,7 @@
return true;
}
+ @ReservedStackAccess
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
@@ -421,7 +424,8 @@
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null ||
+ rh.tid != LockSupport.getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
@@ -447,6 +451,7 @@
"attempt to unlock read lock, not locked by current thread");
}
+ @ReservedStackAccess
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
@@ -479,7 +484,8 @@
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null ||
+ rh.tid != LockSupport.getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -516,7 +522,8 @@
} else {
if (rh == null) {
rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current)) {
+ if (rh == null ||
+ rh.tid != LockSupport.getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
@@ -537,7 +544,8 @@
} else {
if (rh == null)
rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null ||
+ rh.tid != LockSupport.getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -554,6 +562,7 @@
* This is identical in effect to tryAcquire except for lack
* of calls to writerShouldBlock.
*/
+ @ReservedStackAccess
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
@@ -575,6 +584,7 @@
* This is identical in effect to tryAcquireShared except for
* lack of calls to readerShouldBlock.
*/
+ @ReservedStackAccess
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
@@ -593,7 +603,8 @@
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
+ if (rh == null ||
+ rh.tid != LockSupport.getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@@ -644,7 +655,7 @@
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
- if (rh != null && rh.tid == getThreadId(current))
+ if (rh != null && rh.tid == LockSupport.getThreadId(current))
return rh.count;
int count = readHolds.get().count;
@@ -1490,26 +1501,4 @@
"[Write locks = " + w + ", Read locks = " + r + "]";
}
- /**
- * Returns the thread id for the given thread. We must access
- * this directly rather than via method Thread.getId() because
- * getId() is not final, and has been known to be overridden in
- * ways that do not preserve unique mappings.
- */
- static final long getThreadId(Thread thread) {
- return U.getLongVolatile(thread, TID);
- }
-
- // Unsafe mechanics
- private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
- private static final long TID;
- static {
- try {
- TID = U.objectFieldOffset
- (Thread.class.getDeclaredField("tid"));
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
-
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java Fri Jul 15 14:04:09 2016 -0700
@@ -262,7 +262,6 @@
*
* </ul>
*
- *
* The methods of all classes in {@code java.util.concurrent} and its
* subpackages extend these guarantees to higher-level
* synchronization. In particular:
--- a/jdk/test/java/util/concurrent/tck/Atomic8Test.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/test/java/util/concurrent/tck/Atomic8Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -179,7 +179,7 @@
* result of supplied function
*/
public void testReferenceGetAndUpdate() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+ AtomicReference<Integer> a = new AtomicReference<>(one);
assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17));
assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17));
assertEquals(new Integer(35), a.get());
@@ -190,7 +190,7 @@
* returns result.
*/
public void testReferenceUpdateAndGet() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+ AtomicReference<Integer> a = new AtomicReference<>(one);
assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17));
assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17));
assertEquals(new Integer(35), a.get());
@@ -201,7 +201,7 @@
* with supplied function.
*/
public void testReferenceGetAndAccumulate() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+ AtomicReference<Integer> a = new AtomicReference<>(one);
assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger));
assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger));
assertEquals(new Integer(6), a.get());
@@ -212,7 +212,7 @@
* returns result.
*/
public void testReferenceAccumulateAndGet() {
- AtomicReference<Integer> a = new AtomicReference<Integer>(one);
+ AtomicReference<Integer> a = new AtomicReference<>(one);
assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger));
assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger));
assertEquals(new Integer(10), a.get());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicBoolean9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicBoolean9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicBoolean9Test.class);
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.getPlain());
+ ai.set(false);
+ assertEquals(false, ai.getPlain());
+ ai.set(true);
+ assertEquals(true, ai.getPlain());
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.getOpaque());
+ ai.set(false);
+ assertEquals(false, ai.getOpaque());
+ ai.set(true);
+ assertEquals(true, ai.getOpaque());
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.getAcquire());
+ ai.set(false);
+ assertEquals(false, ai.getAcquire());
+ ai.set(true);
+ assertEquals(true, ai.getAcquire());
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.get());
+ ai.setPlain(false);
+ assertEquals(false, ai.get());
+ ai.setPlain(true);
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.get());
+ ai.setOpaque(false);
+ assertEquals(false, ai.get());
+ ai.setOpaque(true);
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.get());
+ ai.setRelease(false);
+ assertEquals(false, ai.get());
+ ai.setRelease(true);
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.compareAndExchange(true, false));
+ assertEquals(false, ai.compareAndExchange(false, false));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchange(true, true));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchange(false, true));
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.compareAndExchangeAcquire(true, false));
+ assertEquals(false, ai.compareAndExchangeAcquire(false, false));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchangeAcquire(true, true));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchangeAcquire(false, true));
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.compareAndExchangeRelease(true, false));
+ assertEquals(false, ai.compareAndExchangeRelease(false, false));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchangeRelease(true, true));
+ assertEquals(false, ai.get());
+ assertEquals(false, ai.compareAndExchangeRelease(false, true));
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ do {} while (!ai.weakCompareAndSetVolatile(true, false));
+ do {} while (!ai.weakCompareAndSetVolatile(false, false));
+ assertEquals(false, ai.get());
+ do {} while (!ai.weakCompareAndSetVolatile(false, true));
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ do {} while (!ai.weakCompareAndSetAcquire(true, false));
+ do {} while (!ai.weakCompareAndSetAcquire(false, false));
+ assertEquals(false, ai.get());
+ do {} while (!ai.weakCompareAndSetAcquire(false, true));
+ assertEquals(true, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ do {} while (!ai.weakCompareAndSetRelease(true, false));
+ do {} while (!ai.weakCompareAndSetRelease(false, false));
+ assertEquals(false, ai.get());
+ do {} while (!ai.weakCompareAndSetRelease(false, true));
+ assertEquals(true, ai.get());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicInteger9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicInteger9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicInteger9Test.class);
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getPlain());
+ ai.set(2);
+ assertEquals(2, ai.getPlain());
+ ai.set(-3);
+ assertEquals(-3, ai.getPlain());
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getOpaque());
+ ai.set(2);
+ assertEquals(2, ai.getOpaque());
+ ai.set(-3);
+ assertEquals(-3, ai.getOpaque());
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getAcquire());
+ ai.set(2);
+ assertEquals(2, ai.getAcquire());
+ ai.set(-3);
+ assertEquals(-3, ai.getAcquire());
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ ai.setPlain(2);
+ assertEquals(2, ai.get());
+ ai.setPlain(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ ai.setOpaque(2);
+ assertEquals(2, ai.get());
+ ai.setOpaque(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ ai.setRelease(2);
+ assertEquals(2, ai.get());
+ ai.setRelease(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.compareAndExchange(1, 2));
+ assertEquals(2, ai.compareAndExchange(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchange(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchange(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.compareAndExchangeAcquire(1, 2));
+ assertEquals(2, ai.compareAndExchangeAcquire(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeAcquire(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeAcquire(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.compareAndExchangeRelease(1, 2));
+ assertEquals(2, ai.compareAndExchangeRelease(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeRelease(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeRelease(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicInteger ai = new AtomicInteger(1);
+ do {} while (!ai.weakCompareAndSetVolatile(1, 2));
+ do {} while (!ai.weakCompareAndSetVolatile(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetVolatile(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicInteger ai = new AtomicInteger(1);
+ do {} while (!ai.weakCompareAndSetAcquire(1, 2));
+ do {} while (!ai.weakCompareAndSetAcquire(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetAcquire(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicInteger ai = new AtomicInteger(1);
+ do {} while (!ai.weakCompareAndSetRelease(1, 2));
+ do {} while (!ai.weakCompareAndSetRelease(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetRelease(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicIntegerArray9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicIntegerArray9Test extends JSR166TestCase {
+
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicIntegerArray9Test.class);
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ final int j = index;
+ final Runnable[] tasks = {
+ () -> aa.getPlain(j),
+ () -> aa.getOpaque(j),
+ () -> aa.getAcquire(j),
+ () -> aa.setPlain(j, 1),
+ () -> aa.setOpaque(j, 1),
+ () -> aa.setRelease(j, 1),
+ () -> aa.compareAndExchange(j, 1, 2),
+ () -> aa.compareAndExchangeAcquire(j, 1, 2),
+ () -> aa.compareAndExchangeRelease(j, 1, 2),
+ () -> aa.weakCompareAndSetVolatile(j, 1, 2),
+ () -> aa.weakCompareAndSetAcquire(j, 1, 2),
+ () -> aa.weakCompareAndSetRelease(j, 1, 2),
+ };
+
+ assertThrows(IndexOutOfBoundsException.class, tasks);
+ }
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getPlain(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getPlain(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getPlain(i));
+ }
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getOpaque(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getOpaque(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getOpaque(i));
+ }
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAcquire(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getAcquire(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getAcquire(i));
+ }
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setPlain(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setPlain(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setPlain(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setOpaque(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setOpaque(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setOpaque(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setRelease(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setRelease(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setRelease(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchange(i, 1, 2));
+ assertEquals(2, aa.compareAndExchange(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchange(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchange(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchangeAcquire(i, 1, 2));
+ assertEquals(2, aa.compareAndExchangeAcquire(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeAcquire(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeAcquire(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchangeRelease(i, 1, 2));
+ assertEquals(2, aa.compareAndExchangeRelease(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeRelease(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeRelease(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetVolatile(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetVolatile(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetVolatile(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetAcquire(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetAcquire(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetAcquire(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetRelease(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetRelease(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetRelease(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicLong9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicLong9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicLong9Test.class);
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getPlain());
+ ai.set(2);
+ assertEquals(2, ai.getPlain());
+ ai.set(-3);
+ assertEquals(-3, ai.getPlain());
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getOpaque());
+ ai.set(2);
+ assertEquals(2, ai.getOpaque());
+ ai.set(-3);
+ assertEquals(-3, ai.getOpaque());
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getAcquire());
+ ai.set(2);
+ assertEquals(2, ai.getAcquire());
+ ai.set(-3);
+ assertEquals(-3, ai.getAcquire());
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ ai.setPlain(2);
+ assertEquals(2, ai.get());
+ ai.setPlain(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ ai.setOpaque(2);
+ assertEquals(2, ai.get());
+ ai.setOpaque(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ ai.setRelease(2);
+ assertEquals(2, ai.get());
+ ai.setRelease(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.compareAndExchange(1, 2));
+ assertEquals(2, ai.compareAndExchange(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchange(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchange(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.compareAndExchangeAcquire(1, 2));
+ assertEquals(2, ai.compareAndExchangeAcquire(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeAcquire(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeAcquire(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.compareAndExchangeRelease(1, 2));
+ assertEquals(2, ai.compareAndExchangeRelease(2, -4));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeRelease(-5, 7));
+ assertEquals(-4, ai.get());
+ assertEquals(-4, ai.compareAndExchangeRelease(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicLong ai = new AtomicLong(1);
+ do {} while (!ai.weakCompareAndSetVolatile(1, 2));
+ do {} while (!ai.weakCompareAndSetVolatile(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetVolatile(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicLong ai = new AtomicLong(1);
+ do {} while (!ai.weakCompareAndSetAcquire(1, 2));
+ do {} while (!ai.weakCompareAndSetAcquire(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetAcquire(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicLong ai = new AtomicLong(1);
+ do {} while (!ai.weakCompareAndSetRelease(1, 2));
+ do {} while (!ai.weakCompareAndSetRelease(2, -4));
+ assertEquals(-4, ai.get());
+ do {} while (!ai.weakCompareAndSetRelease(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicLongArray9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicLongArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicLongArray9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicLongArray9Test.class);
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ final int j = index;
+ final Runnable[] tasks = {
+ () -> aa.getPlain(j),
+ () -> aa.getOpaque(j),
+ () -> aa.getAcquire(j),
+ () -> aa.setPlain(j, 1),
+ () -> aa.setOpaque(j, 1),
+ () -> aa.setRelease(j, 1),
+ () -> aa.compareAndExchange(j, 1, 2),
+ () -> aa.compareAndExchangeAcquire(j, 1, 2),
+ () -> aa.compareAndExchangeRelease(j, 1, 2),
+ () -> aa.weakCompareAndSetVolatile(j, 1, 2),
+ () -> aa.weakCompareAndSetAcquire(j, 1, 2),
+ () -> aa.weakCompareAndSetRelease(j, 1, 2),
+ };
+
+ assertThrows(IndexOutOfBoundsException.class, tasks);
+ }
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getPlain(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getPlain(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getPlain(i));
+ }
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getOpaque(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getOpaque(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getOpaque(i));
+ }
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAcquire(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.getAcquire(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.getAcquire(i));
+ }
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setPlain(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setPlain(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setPlain(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setOpaque(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setOpaque(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setOpaque(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setRelease(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.setRelease(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.setRelease(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchange(i, 1, 2));
+ assertEquals(2, aa.compareAndExchange(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchange(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchange(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchangeAcquire(i, 1, 2));
+ assertEquals(2, aa.compareAndExchangeAcquire(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeAcquire(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeAcquire(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.compareAndExchangeRelease(i, 1, 2));
+ assertEquals(2, aa.compareAndExchangeRelease(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeRelease(i,-5, 7));
+ assertEquals(-4, aa.get(i));
+ assertEquals(-4, aa.compareAndExchangeRelease(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetVolatile(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetVolatile(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetVolatile(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetAcquire(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetAcquire(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetAcquire(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ do {} while (!aa.weakCompareAndSetRelease(i, 1, 2));
+ do {} while (!aa.weakCompareAndSetRelease(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetRelease(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicReference9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicReference9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicReference9Test.class);
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.getPlain());
+ ai.set(two);
+ assertEquals(two, ai.getPlain());
+ ai.set(m3);
+ assertEquals(m3, ai.getPlain());
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.getOpaque());
+ ai.set(two);
+ assertEquals(two, ai.getOpaque());
+ ai.set(m3);
+ assertEquals(m3, ai.getOpaque());
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.getAcquire());
+ ai.set(two);
+ assertEquals(two, ai.getAcquire());
+ ai.set(m3);
+ assertEquals(m3, ai.getAcquire());
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.get());
+ ai.setPlain(two);
+ assertEquals(two, ai.get());
+ ai.setPlain(m3);
+ assertEquals(m3, ai.get());
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.get());
+ ai.setOpaque(two);
+ assertEquals(two, ai.get());
+ ai.setOpaque(m3);
+ assertEquals(m3, ai.get());
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.get());
+ ai.setRelease(two);
+ assertEquals(two, ai.get());
+ ai.setRelease(m3);
+ assertEquals(m3, ai.get());
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.compareAndExchange(one, two));
+ assertEquals(two, ai.compareAndExchange(two, m4));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchange(m5, seven));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchange(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.compareAndExchangeAcquire(one, two));
+ assertEquals(two, ai.compareAndExchangeAcquire(two, m4));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchangeAcquire(m5, seven));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchangeAcquire(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ assertEquals(one, ai.compareAndExchangeRelease(one, two));
+ assertEquals(two, ai.compareAndExchangeRelease(two, m4));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchangeRelease(m5, seven));
+ assertEquals(m4, ai.get());
+ assertEquals(m4, ai.compareAndExchangeRelease(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ do {} while (!ai.weakCompareAndSetVolatile(one, two));
+ do {} while (!ai.weakCompareAndSetVolatile(two, m4));
+ assertEquals(m4, ai.get());
+ do {} while (!ai.weakCompareAndSetVolatile(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ do {} while (!ai.weakCompareAndSetAcquire(one, two));
+ do {} while (!ai.weakCompareAndSetAcquire(two, m4));
+ assertEquals(m4, ai.get());
+ do {} while (!ai.weakCompareAndSetAcquire(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
+ do {} while (!ai.weakCompareAndSetRelease(one, two));
+ do {} while (!ai.weakCompareAndSetRelease(two, m4));
+ assertEquals(m4, ai.get());
+ do {} while (!ai.weakCompareAndSetRelease(m4, seven));
+ assertEquals(seven, ai.get());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceArray9Test.java Fri Jul 15 14:04:09 2016 -0700
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AtomicReferenceArray9Test extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+ public static Test suite() {
+ return new TestSuite(AtomicReferenceArray9Test.class);
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ final int j = index;
+ final Runnable[] tasks = {
+ () -> aa.getPlain(j),
+ () -> aa.getOpaque(j),
+ () -> aa.getAcquire(j),
+ () -> aa.setPlain(j, null),
+ () -> aa.setOpaque(j, null),
+ () -> aa.setRelease(j, null),
+ () -> aa.compareAndExchange(j, null, null),
+ () -> aa.compareAndExchangeAcquire(j, null, null),
+ () -> aa.compareAndExchangeRelease(j, null, null),
+ () -> aa.weakCompareAndSetVolatile(j, null, null),
+ () -> aa.weakCompareAndSetAcquire(j, null, null),
+ () -> aa.weakCompareAndSetRelease(j, null, null),
+ };
+
+ assertThrows(IndexOutOfBoundsException.class, tasks);
+ }
+ }
+
+ /**
+ * getPlain returns the last value set
+ */
+ public void testGetPlainSet() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.getPlain(i));
+ aa.set(i, two);
+ assertEquals(two, aa.getPlain(i));
+ aa.set(i, m3);
+ assertEquals(m3, aa.getPlain(i));
+ }
+ }
+
+ /**
+ * getOpaque returns the last value set
+ */
+ public void testGetOpaqueSet() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.getOpaque(i));
+ aa.set(i, two);
+ assertEquals(two, aa.getOpaque(i));
+ aa.set(i, m3);
+ assertEquals(m3, aa.getOpaque(i));
+ }
+ }
+
+ /**
+ * getAcquire returns the last value set
+ */
+ public void testGetAcquireSet() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.getAcquire(i));
+ aa.set(i, two);
+ assertEquals(two, aa.getAcquire(i));
+ aa.set(i, m3);
+ assertEquals(m3, aa.getAcquire(i));
+ }
+ }
+
+ /**
+ * get returns the last value setPlain
+ */
+ public void testGetSetPlain() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setPlain(i, one);
+ assertEquals(one, aa.get(i));
+ aa.setPlain(i, two);
+ assertEquals(two, aa.get(i));
+ aa.setPlain(i, m3);
+ assertEquals(m3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setOpaque
+ */
+ public void testGetSetOpaque() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setOpaque(i, one);
+ assertEquals(one, aa.get(i));
+ aa.setOpaque(i, two);
+ assertEquals(two, aa.get(i));
+ aa.setOpaque(i, m3);
+ assertEquals(m3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value setRelease
+ */
+ public void testGetSetRelease() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.setRelease(i, one);
+ assertEquals(one, aa.get(i));
+ aa.setRelease(i, two);
+ assertEquals(two, aa.get(i));
+ aa.setRelease(i, m3);
+ assertEquals(m3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchange succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchange() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.compareAndExchange(i, one, two));
+ assertEquals(two, aa.compareAndExchange(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchange(i,m5, seven));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchange(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeAcquire succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeAcquire() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.compareAndExchangeAcquire(i, one, two));
+ assertEquals(two, aa.compareAndExchangeAcquire(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchangeAcquire(i,m5, seven));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchangeAcquire(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndExchangeRelease succeeds in changing value if equal to
+ * expected else fails
+ */
+ public void testCompareAndExchangeRelease() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertEquals(one, aa.compareAndExchangeRelease(i, one, two));
+ assertEquals(two, aa.compareAndExchangeRelease(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchangeRelease(i,m5, seven));
+ assertEquals(m4, aa.get(i));
+ assertEquals(m4, aa.compareAndExchangeRelease(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetVolatile succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetVolatile() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ do {} while (!aa.weakCompareAndSetVolatile(i, one, two));
+ do {} while (!aa.weakCompareAndSetVolatile(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetVolatile(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetAcquire succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetAcquire() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ do {} while (!aa.weakCompareAndSetAcquire(i, one, two));
+ do {} while (!aa.weakCompareAndSetAcquire(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetAcquire(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * repeated weakCompareAndSetRelease succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSetRelease() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ do {} while (!aa.weakCompareAndSetRelease(i, one, two));
+ do {} while (!aa.weakCompareAndSetRelease(i, two, m4));
+ assertEquals(m4, aa.get(i));
+ do {} while (!aa.weakCompareAndSetRelease(i, m4, seven));
+ assertEquals(seven, aa.get(i));
+ }
+ }
+
+}
--- a/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceArrayTest.java Fri Jul 15 14:04:09 2016 -0700
@@ -243,4 +243,5 @@
AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
assertEquals(Arrays.toString(a), aa.toString());
}
+
}
--- a/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/test/java/util/concurrent/tck/AtomicReferenceTest.java Fri Jul 15 14:04:09 2016 -0700
@@ -161,7 +161,7 @@
* toString returns current value.
*/
public void testToString() {
- AtomicReference<Integer> ai = new AtomicReference<Integer>(one);
+ AtomicReference<Integer> ai = new AtomicReference<>(one);
assertEquals(one.toString(), ai.toString());
ai.set(two);
assertEquals(two.toString(), ai.toString());
--- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java Fri Jul 15 13:59:58 2016 -0700
+++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java Fri Jul 15 14:04:09 2016 -0700
@@ -548,6 +548,13 @@
// Java9+ test classes
if (atLeastJava9()) {
String[] java9TestClassNames = {
+ "AtomicBoolean9Test",
+ "AtomicInteger9Test",
+ "AtomicIntegerArray9Test",
+ "AtomicLong9Test",
+ "AtomicLongArray9Test",
+ "AtomicReference9Test",
+ "AtomicReferenceArray9Test",
"ExecutorCompletionService9Test",
};
addNamedTestClasses(suite, java9TestClassNames);
@@ -975,7 +982,11 @@
}
}
- /** Like Runnable, but with the freedom to throw anything */
+ /**
+ * Like Runnable, but with the freedom to throw anything.
+ * junit folks had the same idea:
+ * http://junit.org/junit5/docs/snapshot/api/org/junit/gen5/api/Executable.html
+ */
interface Action { public void run() throws Throwable; }
/**
@@ -1006,6 +1017,15 @@
* Uninteresting threads are filtered out.
*/
static void dumpTestThreads() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ System.setSecurityManager(null);
+ } catch (SecurityException giveUp) {
+ return;
+ }
+ }
+
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.err.println("------ stacktrace dump start ------");
for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
@@ -1023,6 +1043,8 @@
System.err.print(info);
}
System.err.println("------ stacktrace dump end ------");
+
+ if (sm != null) System.setSecurityManager(sm);
}
/**