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
This commit is contained in:
Doug Lea 2016-07-15 14:04:09 -07:00
parent a09ddefd05
commit 14d4754bdd
48 changed files with 3971 additions and 1288 deletions

View File

@ -124,7 +124,6 @@ package java.util;
* 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>.

View File

@ -68,6 +68,7 @@ import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;
import jdk.internal.misc.Unsafe;
/**
* A hash table supporting full concurrency of retrievals and
@ -747,7 +748,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
/* ---------------- Table element access -------------- */
/*
* Volatile access methods are used for table elements as well as
* Atomic access methods are used for table elements as well as
* elements of in-progress next table while resizing. All uses of
* the tab arguments must be null checked by callers. All callers
* also paranoically precheck that tab's length is not zero (or an
@ -757,14 +758,12 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
* 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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
}
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 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
return true;
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private static final long LOCKSTATE;
static {
try {
@ -6341,7 +6340,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
}
// 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;

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
@ -292,64 +294,23 @@ public class ConcurrentLinkedDeque<E>
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 @@ public class ConcurrentLinkedDeque<E>
continue restartFromHead;
else {
// p is first node
newNode.lazySetNext(p); // CAS piggyback
if (p.casPrev(null, newNode)) {
NEXT.set(newNode, p); // CAS piggyback
if (PREV.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != h) // hop two nodes at a time
casHead(h, newNode); // Failure is OK.
if (p != h) // hop two nodes at a time; failure is OK
HEAD.weakCompareAndSetVolatile(this, h, newNode);
return;
}
// Lost CAS race to another thread; re-read prev
@ -381,7 +342,7 @@ public class ConcurrentLinkedDeque<E>
* 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 @@ public class ConcurrentLinkedDeque<E>
continue restartFromTail;
else {
// p is last node
newNode.lazySetPrev(p); // CAS piggyback
if (p.casNext(null, newNode)) {
PREV.set(newNode, p); // CAS piggyback
if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
if (p != t) // hop two nodes at a time; failure is OK
TAIL.weakCompareAndSetVolatile(this, t, newNode);
return;
}
// Lost CAS race to another thread; re-read next
@ -516,8 +477,8 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure x is not reachable from tail
// Finally, actually gc-unlink
x.lazySetPrev(isFirst ? prevTerminator() : x);
x.lazySetNext(isLast ? nextTerminator() : x);
PREV.setRelease(x, isFirst ? prevTerminator() : x);
NEXT.setRelease(x, isLast ? nextTerminator() : x);
}
}
}
@ -531,7 +492,8 @@ public class ConcurrentLinkedDeque<E>
// 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 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
o.lazySetNext(o);
o.lazySetPrev(prevTerminator());
NEXT.setRelease(o, o);
PREV.setRelease(o, prevTerminator());
}
}
return;
@ -565,7 +527,8 @@ public class ConcurrentLinkedDeque<E>
// 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 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
o.lazySetPrev(o);
o.lazySetNext(nextTerminator());
PREV.setRelease(o, o);
NEXT.setRelease(o, nextTerminator());
}
}
return;
@ -607,7 +570,7 @@ public class ConcurrentLinkedDeque<E>
(q = (p = q).prev) == null) {
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
if (casHead(h, p))
if (HEAD.compareAndSet(this, h, p))
return;
else
continue restartFromHead;
@ -637,7 +600,7 @@ public class ConcurrentLinkedDeque<E>
(q = (p = q).next) == null) {
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
if (casTail(t, p))
if (TAIL.compareAndSet(this, t, p))
return;
else
continue restartFromTail;
@ -675,7 +638,7 @@ public class ConcurrentLinkedDeque<E>
}
// found active CAS target
if (prev == p || x.casPrev(prev, p))
if (prev == p || PREV.compareAndSet(x, prev, p))
return;
} while (x.item != null || x.next == null);
@ -706,7 +669,7 @@ public class ConcurrentLinkedDeque<E>
}
// found active CAS target
if (next == p || x.casNext(next, p))
if (next == p || NEXT.compareAndSet(x, next, p))
return;
} while (x.item != null || x.prev == null);
@ -751,7 +714,7 @@ public class ConcurrentLinkedDeque<E>
else if (p == h
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casHead(h, p))
|| HEAD.compareAndSet(this, h, p))
return p;
else
continue restartFromHead;
@ -776,7 +739,7 @@ public class ConcurrentLinkedDeque<E>
else if (p == t
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casTail(t, p))
|| TAIL.compareAndSet(this, t, p))
return p;
else
continue restartFromTail;
@ -802,7 +765,7 @@ public class ConcurrentLinkedDeque<E>
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
head = tail = new Node<E>(null);
head = tail = new Node<E>();
}
/**
@ -818,12 +781,12 @@ public class ConcurrentLinkedDeque<E>
// 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 @@ public class ConcurrentLinkedDeque<E>
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 class ConcurrentLinkedDeque<E>
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 class ConcurrentLinkedDeque<E>
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 @@ public class ConcurrentLinkedDeque<E>
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 @@ public class ConcurrentLinkedDeque<E>
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 @@ public class ConcurrentLinkedDeque<E>
// 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 @@ public class ConcurrentLinkedDeque<E>
continue restartFromTail;
else {
// p is last node
beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
if (p.casNext(null, beginningOfTheEnd)) {
PREV.set(beginningOfTheEnd, p); // CAS piggyback
if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this deque.
if (!casTail(t, last)) {
if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
casTail(t, last);
TAIL.weakCompareAndSetVolatile(this, t, last);
}
return true;
}
@ -1586,41 +1551,38 @@ public class ConcurrentLinkedDeque<E>
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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -166,9 +168,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* this is merely an optimization.
*
* When constructing a Node (before enqueuing it) we avoid paying
* for a volatile write to item by using Unsafe.putObject instead
* of a normal write. This allows the cost of enqueue to be
* "one-and-a-half" CASes.
* for a volatile write to item. This allows the cost of enqueue
* to be "one-and-a-half" CASes.
*
* Both head and tail may or may not point to a Node with a
* non-null item. If the queue is empty, all items must of course
@ -178,33 +179,21 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (h == null)
h = t = newNode;
else {
lazySetNext(t, newNode);
NEXT.set(t, newNode);
t = newNode;
}
}
@ -286,8 +275,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
*/
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
next = succ(p);
continue;
}
removed = casItem(p, item, null);
removed = ITEM.compareAndSet(p, item, null);
}
next = succ(p);
if (pred != null && next != null) // unlink
casNext(pred, p, next);
NEXT.weakCompareAndSetVolatile(pred, p, next);
if (removed)
return true;
}
@ -520,7 +509,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
lazySetNext(last, newNode);
NEXT.set(last, newNode);
last = newNode;
}
}
@ -532,15 +521,15 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
// unlink deleted nodes
if ((q = succ(p)) != null)
casNext(pred, p, q);
NEXT.compareAndSet(pred, p, q);
}
}
@ -801,7 +790,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (h == null)
h = t = newNode;
else {
lazySetNext(t, newNode);
NEXT.set(t, newNode);
t = newNode;
}
}
@ -919,31 +908,20 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
@ -401,7 +403,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* 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 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return node.value != null && casRight(succ, succ.right);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long RIGHT;
// VarHandle mechanics
private static final VarHandle RIGHT;
static {
try {
RIGHT = U.objectFieldOffset
(Index.class.getDeclaredField("right"));
MethodHandles.Lookup l = MethodHandles.lookup();
RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -3607,13 +3604,13 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
}
// 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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
@ -507,15 +509,16 @@ public class ConcurrentSkipListSet<E>
// 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);
}

View File

@ -34,6 +34,7 @@
package java.util.concurrent;
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
@ -1541,17 +1542,21 @@ public class CopyOnWriteArrayList<E>
}
}
// 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);
}
}

View File

@ -35,6 +35,9 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* A {@link ForkJoinTask} with a completion action performed when
* triggered and there are no remaining pending actions.
@ -524,7 +527,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
U.getAndAddInt(this, PENDING, delta);
PENDING.getAndAdd(this, delta);
}
/**
@ -536,7 +539,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
* @return {@code true} if successful
*/
public final boolean compareAndSetPendingCount(int expected, int count) {
return U.compareAndSwapInt(this, PENDING, expected, count);
return PENDING.compareAndSet(this, expected, count);
}
/**
@ -548,7 +551,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
public final int decrementPendingCountUnlessZero() {
int c;
do {} while ((c = pending) != 0 &&
!U.compareAndSwapInt(this, PENDING, c, c - 1));
!PENDING.weakCompareAndSetVolatile(this, c, c - 1));
return c;
}
@ -581,7 +584,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
return;
}
}
else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@ -604,7 +607,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
return;
}
}
else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@ -649,7 +652,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
for (int c;;) {
if ((c = pending) == 0)
return this;
else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(this, c, c - 1))
return null;
}
}
@ -753,13 +756,13 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
*/
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);
}

View File

@ -36,6 +36,10 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
* A synchronization point at which threads can pair and swap elements
* within pairs. Each thread presents some object on entry to the
@ -155,9 +159,7 @@ public class Exchanger<V> {
* a value that is enough for common platforms. Additionally,
* extra care elsewhere is taken to avoid other false/unintended
* sharing and to enhance locality, including adding padding (via
* @Contended) to Nodes, embedding "bound" as an Exchanger field,
* and reworking some park/unpark mechanics compared to
* LockSupport versions.
* @Contended) to Nodes, embedding "bound" as an Exchanger field.
*
* The arena starts out with only one used slot. We expand the
* effective arena size by tracking collisions; i.e., failed CASes
@ -234,12 +236,12 @@ public class Exchanger<V> {
* because most of the logic relies on reads of fields that are
* maintained as local variables so can't be nicely factored --
* mainly, here, bulky spin->yield->block/cancel code), and
* heavily dependent on intrinsics (Unsafe) to use inlined
* heavily dependent on intrinsics (VarHandles) to use inlined
* embedded CAS and related memory access operations (that tend
* not to be as readily inlined by dynamic compilers when they are
* hidden behind other methods that would more nicely name and
* encapsulate the intended effects). This includes the use of
* putXRelease to clear fields of the per-thread Nodes between
* setRelease to clear fields of the per-thread Nodes between
* uses. Note that field Node.item is not declared as volatile
* even though it is read by releasing threads, because they only
* do so after CAS operations that must precede access, and all
@ -252,10 +254,10 @@ public class Exchanger<V> {
*/
/**
* The byte distance (as a shift value) between any two used slots
* in the arena. 1 << ASHIFT should be at least cacheline size.
* The index distance (as a shift value) between any two used slots
* in the arena, spacing them out to avoid false sharing.
*/
private static final int ASHIFT = 7;
private static final int ASHIFT = 5;
/**
* The maximum supported arena index. The maximum allocatable
@ -356,27 +358,31 @@ public class Exchanger<V> {
*/
private final Object arenaExchange(Object item, boolean timed, long ns) {
Node[] a = arena;
int alen = a.length;
Node p = participant.get();
for (int i = p.index;;) { // access slot at i
int b, m, c; long j; // j is raw array offset
Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
if (q != null && U.compareAndSwapObject(a, j, q, null)) {
int b, m, c;
int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
if (j < 0 || j >= alen)
j = alen - 1;
Node q = (Node)AA.getAcquire(a, j);
if (q != null && AA.compareAndSet(a, j, q, null)) {
Object v = q.item; // release
q.match = item;
Thread w = q.parked;
if (w != null)
U.unpark(w);
LockSupport.unpark(w);
return v;
}
else if (i <= (m = (b = bound) & MMASK) && q == null) {
p.item = item; // offer
if (U.compareAndSwapObject(a, j, null, p)) {
if (AA.compareAndSet(a, j, null, p)) {
long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
Thread t = Thread.currentThread(); // wait
for (int h = p.hash, spins = SPINS;;) {
Object v = p.match;
if (v != null) {
U.putObjectRelease(p, MATCH, null);
MATCH.setRelease(p, null);
p.item = null; // clear for next use
p.hash = h;
return v;
@ -389,22 +395,24 @@ public class Exchanger<V> {
(--spins & ((SPINS >>> 1) - 1)) == 0)
Thread.yield(); // two yields per wait
}
else if (U.getObjectVolatile(a, j) != p)
else if (AA.getAcquire(a, j) != p)
spins = SPINS; // releaser hasn't set match yet
else if (!t.isInterrupted() && m == 0 &&
(!timed ||
(ns = end - System.nanoTime()) > 0L)) {
U.putObject(t, BLOCKER, this); // emulate LockSupport
p.parked = t; // minimize window
if (U.getObjectVolatile(a, j) == p)
U.park(false, ns);
if (AA.getAcquire(a, j) == p) {
if (ns == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, ns);
}
p.parked = null;
U.putObject(t, BLOCKER, null);
}
else if (U.getObjectVolatile(a, j) == p &&
U.compareAndSwapObject(a, j, p, null)) {
else if (AA.getAcquire(a, j) == p &&
AA.compareAndSet(a, j, p, null)) {
if (m != 0) // try to shrink
U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
BOUND.compareAndSet(this, b, b + SEQ - 1);
p.item = null;
p.hash = h;
i = p.index >>>= 1; // descend
@ -426,7 +434,7 @@ public class Exchanger<V> {
i = (i != m || m == 0) ? m : m - 1;
}
else if ((c = p.collides) < m || m == FULL ||
!U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
!BOUND.compareAndSet(this, b, b + SEQ + 1)) {
p.collides = c + 1;
i = (i == 0) ? m : i - 1; // cyclically traverse
}
@ -455,24 +463,24 @@ public class Exchanger<V> {
for (Node q;;) {
if ((q = slot) != null) {
if (U.compareAndSwapObject(this, SLOT, q, null)) {
if (SLOT.compareAndSet(this, q, null)) {
Object v = q.item;
q.match = item;
Thread w = q.parked;
if (w != null)
U.unpark(w);
LockSupport.unpark(w);
return v;
}
// create arena on contention, but continue until slot null
if (NCPU > 1 && bound == 0 &&
U.compareAndSwapInt(this, BOUND, 0, SEQ))
BOUND.compareAndSet(this, 0, SEQ))
arena = new Node[(FULL + 2) << ASHIFT];
}
else if (arena != null)
return null; // caller must reroute to arenaExchange
else {
p.item = item;
if (U.compareAndSwapObject(this, SLOT, null, p))
if (SLOT.compareAndSet(this, null, p))
break;
p.item = null;
}
@ -495,19 +503,21 @@ public class Exchanger<V> {
spins = SPINS;
else if (!t.isInterrupted() && arena == null &&
(!timed || (ns = end - System.nanoTime()) > 0L)) {
U.putObject(t, BLOCKER, this);
p.parked = t;
if (slot == p)
U.park(false, ns);
if (slot == p) {
if (ns == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, ns);
}
p.parked = null;
U.putObject(t, BLOCKER, null);
}
else if (U.compareAndSwapObject(this, SLOT, p, null)) {
else if (SLOT.compareAndSet(this, p, null)) {
v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
break;
}
}
U.putObjectRelease(p, MATCH, null);
MATCH.setRelease(p, null);
p.item = null;
p.hash = h;
return v;
@ -556,8 +566,9 @@ public class Exchanger<V> {
@SuppressWarnings("unchecked")
public V exchange(V x) throws InterruptedException {
Object v;
Node[] a;
Object item = (x == null) ? NULL_ITEM : x; // translate null args
if ((arena != null ||
if (((a = arena) != null ||
(v = slotExchange(item, false, 0L)) == null) &&
((Thread.interrupted() || // disambiguates null return
(v = arenaExchange(item, false, 0L)) == null)))
@ -623,31 +634,18 @@ public class Exchanger<V> {
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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
@ -69,9 +71,6 @@ public class FutureTask<V> implements RunnableFuture<V> {
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
*
* Style note: As usual, we bypass overhead of using
* AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
@ -163,9 +162,8 @@ public class FutureTask<V> implements RunnableFuture<V> {
}
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
if (!(state == NEW && STATE.compareAndSet
(this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
@ -174,7 +172,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (t != null)
t.interrupt();
} finally { // final state
U.putIntRelease(this, STATE, INTERRUPTED);
STATE.setRelease(this, INTERRUPTED);
}
}
} finally {
@ -228,9 +226,9 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @param v the value
*/
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = v;
U.putIntRelease(this, STATE, NORMAL); // final state
STATE.setRelease(this, NORMAL); // final state
finishCompletion();
}
}
@ -246,16 +244,16 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @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 @@ public class FutureTask<V> implements RunnableFuture<V> {
*/
protected boolean runAndReset() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
!RUNNER.compareAndSet(this, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
@ -363,7 +361,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
if (WAITERS.weakCompareAndSetVolatile(this, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
@ -425,8 +423,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
q = new WaitNode();
}
else if (!queued)
queued = U.compareAndSwapObject(this, WAITERS,
q.next = waiters, q);
queued = WAITERS.weakCompareAndSetVolatile(this, q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) { // first time
@ -475,7 +472,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (pred.thread == null) // check for race
continue retry;
}
else if (!U.compareAndSwapObject(this, WAITERS, q, s))
else if (!WAITERS.compareAndSet(this, q, s))
continue retry;
}
break;
@ -483,19 +480,16 @@ public class FutureTask<V> implements RunnableFuture<V> {
}
}
// 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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -444,7 +446,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
/**
* Queue nodes. Uses Object, not E, for items to allow forgetting
* them after use. Relies heavily on Unsafe mechanics to minimize
* them after use. Relies heavily on VarHandles to minimize
* unnecessary ordering constraints: Writes that are intrinsically
* ordered wrt other accesses or CASes use simple relaxed forms.
*/
@ -456,12 +458,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
// CAS methods for fields
final boolean casNext(Node cmp, Node val) {
return U.compareAndSwapObject(this, NEXT, cmp, val);
return NEXT.compareAndSet(this, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class;
return U.compareAndSwapObject(this, ITEM, cmp, val);
return ITEM.compareAndSet(this, cmp, val);
}
/**
@ -469,7 +471,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
U.putObject(this, ITEM, item); // relaxed write
ITEM.set(this, item); // relaxed write
this.isData = isData;
}
@ -478,7 +480,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* only after CASing head field, so uses relaxed write.
*/
final void forgetNext() {
U.putObject(this, NEXT, this);
NEXT.set(this, this);
}
/**
@ -491,8 +493,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* else we don't care).
*/
final void forgetContents() {
U.putObject(this, ITEM, this);
U.putObject(this, WAITER, null);
ITEM.set(this, this);
WAITER.set(this, null);
}
/**
@ -537,19 +539,16 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
private static final long serialVersionUID = -3375979862319811754L;
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long ITEM;
private static final long NEXT;
private static final long WAITER;
// VarHandle mechanics
private static final VarHandle ITEM;
private static final VarHandle NEXT;
private static final VarHandle WAITER;
static {
try {
ITEM = U.objectFieldOffset
(Node.class.getDeclaredField("item"));
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
WAITER = U.objectFieldOffset
(Node.class.getDeclaredField("waiter"));
MethodHandles.Lookup l = MethodHandles.lookup();
ITEM = l.findVarHandle(Node.class, "item", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -567,15 +566,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
return U.compareAndSwapObject(this, TAIL, cmp, val);
return TAIL.compareAndSet(this, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
return U.compareAndSwapObject(this, HEAD, cmp, val);
return HEAD.compareAndSet(this, cmp, val);
}
private boolean casSweepVotes(int cmp, int val) {
return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
return SWEEPVOTES.compareAndSet(this, cmp, val);
}
/*
@ -1562,20 +1561,19 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
}
}
// 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);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
@ -221,7 +223,6 @@ import java.util.concurrent.locks.LockSupport;
* phaser.arriveAndDeregister();
* }}</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 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
if (STATE.compareAndSet(this, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@ -397,12 +398,12 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
U.compareAndSwapLong(this, STATE, s, n);
STATE.compareAndSet(this, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
U.compareAndSwapLong(this, STATE, s, s | EMPTY);
STATE.compareAndSet(this, s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@ -437,13 +438,13 @@ public class Phaser {
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
else if (STATE.compareAndSet(this, s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
if (U.compareAndSwapLong(this, STATE, s, next))
if (STATE.compareAndSet(this, s, next))
break;
}
else {
@ -455,8 +456,8 @@ public class Phaser {
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
while (!U.compareAndSwapLong
(this, STATE, s,
while (!STATE.weakCompareAndSetVolatile
(this, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@ -487,8 +488,8 @@ public class Phaser {
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
!U.compareAndSwapLong
(this, STATE, s,
!STATE.weakCompareAndSetVolatile
(this, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@ -677,7 +678,7 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@ -692,7 +693,7 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
if (!U.compareAndSwapLong(this, STATE, s, n))
if (!STATE.compareAndSet(this, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@ -808,7 +809,7 @@ public class Phaser {
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@ -1043,6 +1044,8 @@ public class Phaser {
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
else
Thread.onSpinWait();
}
else if (node.isReleasable()) // done or aborted
break;
@ -1131,14 +1134,12 @@ public class Phaser {
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
// VarHandle mechanics
private static final VarHandle STATE;
static {
try {
STATE = U.objectFieldOffset
(Phaser.class.getDeclaredField("state"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(Phaser.class, "state", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -289,7 +291,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@ -1009,13 +1011,14 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
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);
}

View File

@ -36,6 +36,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Collections;
@ -247,7 +249,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
U.compareAndSwapObject(this, NEXT, cmp, val);
SNEXT.compareAndSet(this, cmp, val);
}
/**
@ -260,7 +262,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
boolean tryMatch(SNode s) {
if (match == null &&
U.compareAndSwapObject(this, MATCH, null, s)) {
SMATCH.compareAndSet(this, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@ -275,24 +277,21 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
U.compareAndSwapObject(this, MATCH, null, this);
SMATCH.compareAndSet(this, null, this);
}
boolean isCancelled() {
return match == this;
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long MATCH;
private static final long NEXT;
// VarHandle mechanics
private static final VarHandle SMATCH;
private static final VarHandle SNEXT;
static {
try {
MATCH = U.objectFieldOffset
(SNode.class.getDeclaredField("match"));
NEXT = U.objectFieldOffset
(SNode.class.getDeclaredField("next"));
MethodHandles.Lookup l = MethodHandles.lookup();
SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -304,7 +303,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casHead(SNode h, SNode nh) {
return h == head &&
U.compareAndSwapObject(this, HEAD, h, nh);
SHEAD.compareAndSet(this, h, nh);
}
/**
@ -451,8 +450,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
continue;
}
}
if (spins > 0)
if (spins > 0) {
Thread.onSpinWait();
spins = shouldSpin(s) ? (spins - 1) : 0;
}
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
@ -508,13 +509,12 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
// VarHandle mechanics
private static final VarHandle SHEAD;
static {
try {
HEAD = U.objectFieldOffset
(TransferStack.class.getDeclaredField("head"));
MethodHandles.Lookup l = MethodHandles.lookup();
SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -546,19 +546,19 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
U.compareAndSwapObject(this, NEXT, cmp, val);
QNEXT.compareAndSet(this, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
U.compareAndSwapObject(this, ITEM, cmp, val);
QITEM.compareAndSet(this, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
U.compareAndSwapObject(this, ITEM, cmp, this);
QITEM.compareAndSet(this, cmp, this);
}
boolean isCancelled() {
@ -574,17 +574,14 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
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 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
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 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
U.compareAndSwapObject(this, TAIL, t, nt);
QTAIL.compareAndSet(this, t, nt);
}
/**
@ -631,7 +628,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
U.compareAndSwapObject(this, CLEANME, cmp, val);
QCLEANME.compareAndSet(this, cmp, val);
}
/**
@ -752,8 +749,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
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 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
}
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);
}

View File

@ -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 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicBoolean implements java.io.Serializable {
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));
}
}

View File

@ -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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
* @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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
* @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 class AtomicInteger extends Number implements java.io.Serializable {
*/
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 class AtomicInteger extends Number implements java.io.Serializable {
*/
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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* 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);
}
}

View File

@ -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 @@ public class AtomicIntegerArray implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @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 class AtomicIntegerArray implements java.io.Serializable {
*/
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 class AtomicIntegerArray implements java.io.Serializable {
*/
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 @@ public class AtomicIntegerArray implements java.io.Serializable {
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);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
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 class AtomicIntegerFieldUpdater<T> {
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 @@ public abstract class AtomicIntegerFieldUpdater<T> {
*/
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

View File

@ -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 @@ public class AtomicLong extends Number implements java.io.Serializable {
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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLong extends Number implements java.io.Serializable {
* @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 @@ public class AtomicLong extends Number implements java.io.Serializable {
* @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 class AtomicLong extends Number implements java.io.Serializable {
*/
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 class AtomicLong extends Number implements java.io.Serializable {
*/
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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* 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);
}
}

View File

@ -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 @@ public class AtomicLongArray implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicLongArray implements java.io.Serializable {
* @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 @@ public class AtomicLongArray implements java.io.Serializable {
* @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 class AtomicLongArray implements java.io.Serializable {
*/
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 class AtomicLongArray implements java.io.Serializable {
*/
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 @@ public class AtomicLongArray implements java.io.Serializable {
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);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
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 class AtomicLongFieldUpdater<T> {
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 @@ public abstract class AtomicLongFieldUpdater<T> {
}
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 @@ public abstract class AtomicLongFieldUpdater<T> {
}
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

View File

@ -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 @@ public class AtomicMarkableReference<V> {
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);
}
}

View File

@ -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 @@ public class AtomicReference<V> implements java.io.Serializable {
}
/**
* 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 @@ public class AtomicReference<V> implements java.io.Serializable {
}
/**
* 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);
VALUE.setRelease(this, 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
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @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(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 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(V expect, V update) {
return U.compareAndSwapObject(this, VALUE, expect, update);
public final boolean weakCompareAndSet(V expectedValue, V newValue) {
return VALUE.weakCompareAndSet(this, expectedValue, 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
*/
@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 @@ public class AtomicReference<V> implements java.io.Serializable {
* @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 @@ public class AtomicReference<V> implements java.io.Serializable {
* @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 class AtomicReference<V> implements java.io.Serializable {
*/
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 class AtomicReference<V> implements java.io.Serializable {
*/
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 @@ public class AtomicReference<V> implements java.io.Serializable {
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);
}
}

View File

@ -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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
}
/**
* 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 E get(int i) {
return getRaw(checkedByteOffset(i));
}
@SuppressWarnings("unchecked")
private E getRaw(long offset) {
return (E) U.getObjectVolatile(array, offset);
public final E get(int i) {
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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
*/
@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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @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 class AtomicReferenceArray<E> implements java.io.Serializable {
*/
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 class AtomicReferenceArray<E> implements java.io.Serializable {
*/
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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
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 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
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);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
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 class AtomicReferenceFieldUpdater<T,V> {
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 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
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

View File

@ -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 @@ public class AtomicStampedReference<V> {
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);
}
}

View File

@ -68,7 +68,7 @@ import java.util.function.LongBinaryOperator;
* <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

View File

@ -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 @@ abstract class Striped64 extends Number {
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 @@ abstract class Striped64 extends Number {
* 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 @@ abstract class Striped64 extends Number {
}
}
// 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) {

View File

@ -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&trade; Language Specification</cite></a>:
* <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.
*
* <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.
*
* <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.
*
* <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>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.
*
* <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;

View File

@ -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 @@ public abstract class AbstractQueuedLongSynchronizer
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 @@ public abstract class AbstractQueuedLongSynchronizer
* 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 @@ public abstract class AbstractQueuedLongSynchronizer
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 @@ public abstract class AbstractQueuedLongSynchronizer
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 @@ public abstract class AbstractQueuedLongSynchronizer
}
}
/**
* 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 @@ public abstract class AbstractQueuedLongSynchronizer
*/
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 @@ public abstract class AbstractQueuedLongSynchronizer
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return U.compareAndSwapObject(this, TAIL, expect, update);
return TAIL.compareAndSet(this, expect, update);
}
}

View File

@ -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 @@ public abstract class AbstractQueuedSynchronizer
/** 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);
}
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;
final void setPrevRelaxed(Node p) {
PREV.set(this, p);
}
// 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 @@ public abstract class AbstractQueuedSynchronizer
* 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 @@ public abstract class AbstractQueuedSynchronizer
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 @@ public abstract class AbstractQueuedSynchronizer
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 @@ public abstract class AbstractQueuedSynchronizer
* @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 @@ public abstract class AbstractQueuedSynchronizer
* {@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 @@ public abstract class AbstractQueuedSynchronizer
* 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 @@ public abstract class AbstractQueuedSynchronizer
* 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 @@ public abstract class AbstractQueuedSynchronizer
}
}
/**
* 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 @@ public abstract class AbstractQueuedSynchronizer
*/
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 @@ public abstract class AbstractQueuedSynchronizer
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return U.compareAndSwapObject(this, TAIL, expect, update);
return TAIL.compareAndSet(this, expect, update);
}
}

View File

@ -396,7 +396,6 @@ public interface Condition {
* 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 @@ public interface Condition {
* 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

View File

@ -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 @@ public class LockSupport {
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);
}

View File

@ -79,7 +79,6 @@ package java.util.concurrent.locks;
* 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.

View File

@ -118,12 +118,6 @@ public class ReentrantLock implements Lock, java.io.Serializable {
abstract static class Sync extends AbstractQueuedSynchronizer {
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 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
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 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
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 @@ public class ReentrantLock implements Lock, java.io.Serializable {
* at which time the lock hold count is set to one.
*/
public void lock() {
sync.lock();
sync.acquire(1);
}
/**

View File

@ -37,6 +37,7 @@ package java.util.concurrent.locks;
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 @@ public class ReentrantReadWriteLock
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 @@ public class ReentrantReadWriteLock
* 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 @@ public class ReentrantReadWriteLock
return free;
}
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
@ -411,6 +413,7 @@ public class ReentrantReadWriteLock
return true;
}
@ReservedStackAccess
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
@ -421,7 +424,8 @@ public class ReentrantReadWriteLock
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 @@ public class ReentrantReadWriteLock
"attempt to unlock read lock, not locked by current thread");
}
@ReservedStackAccess
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
@ -479,7 +484,8 @@ public class ReentrantReadWriteLock
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 @@ public class ReentrantReadWriteLock
} 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 @@ public class ReentrantReadWriteLock
} 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 @@ public class ReentrantReadWriteLock
* 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 @@ public class ReentrantReadWriteLock
* 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 @@ public class ReentrantReadWriteLock
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 @@ public class ReentrantReadWriteLock
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 @@ public class ReentrantReadWriteLock
"[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);
}
}
}

View File

@ -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:

View File

@ -179,7 +179,7 @@ public class Atomic8Test extends JSR166TestCase {
* 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 @@ public class Atomic8Test extends JSR166TestCase {
* 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 @@ public class Atomic8Test extends JSR166TestCase {
* 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 @@ public class Atomic8Test extends JSR166TestCase {
* 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());

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}
}

View File

@ -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());
}
}

View File

@ -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));
}
}
}

View File

@ -243,4 +243,5 @@ public class AtomicReferenceArrayTest extends JSR166TestCase {
AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
assertEquals(Arrays.toString(a), aa.toString());
}
}

View File

@ -161,7 +161,7 @@ public class AtomicReferenceTest extends JSR166TestCase {
* 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());

View File

@ -548,6 +548,13 @@ public class JSR166TestCase extends TestCase {
// Java9+ test classes
if (atLeastJava9()) {
String[] java9TestClassNames = {
"AtomicBoolean9Test",
"AtomicInteger9Test",
"AtomicIntegerArray9Test",
"AtomicLong9Test",
"AtomicLongArray9Test",
"AtomicReference9Test",
"AtomicReferenceArray9Test",
"ExecutorCompletionService9Test",
};
addNamedTestClasses(suite, java9TestClassNames);
@ -975,7 +982,11 @@ public class JSR166TestCase extends TestCase {
}
}
/** 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 @@ public class JSR166TestCase extends TestCase {
* 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 @@ public class JSR166TestCase extends TestCase {
System.err.print(info);
}
System.err.println("------ stacktrace dump end ------");
if (sm != null) System.setSecurityManager(sm);
}
/**