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:
parent
a09ddefd05
commit
14d4754bdd
@ -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>.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -35,26 +35,10 @@
|
||||
|
||||
/**
|
||||
* A small toolkit of classes that support lock-free thread-safe
|
||||
* programming on single variables. In essence, the classes in this
|
||||
* package extend the notion of {@code volatile} values, fields, and
|
||||
* array elements to those that also provide an atomic conditional update
|
||||
* operation of the form:
|
||||
*
|
||||
* <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
|
||||
*
|
||||
* <p>This method (which varies in argument types across different
|
||||
* classes) atomically sets a variable to the {@code updateValue} if it
|
||||
* currently holds the {@code expectedValue}, reporting {@code true} on
|
||||
* success. The classes in this package also contain methods to get and
|
||||
* unconditionally set values, as well as a weaker conditional atomic
|
||||
* update operation {@code weakCompareAndSet} described below.
|
||||
*
|
||||
* <p>The specifications of these methods enable implementations to
|
||||
* employ efficient machine-level atomic instructions that are available
|
||||
* on contemporary processors. However on some platforms, support may
|
||||
* entail some form of internal locking. Thus the methods are not
|
||||
* strictly guaranteed to be non-blocking --
|
||||
* a thread may block transiently before performing the operation.
|
||||
* programming on single variables. Instances of Atomic classes
|
||||
* maintain values that are accessed and updated using methods
|
||||
* otherwise available for fields using associated atomic {@link
|
||||
* java.lang.invoke.VarHandle} operations.
|
||||
*
|
||||
* <p>Instances of classes
|
||||
* {@link java.util.concurrent.atomic.AtomicBoolean},
|
||||
@ -92,45 +76,26 @@
|
||||
* return prev; // return next; for transformAndGet
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>The memory effects for accesses and updates of atomics generally
|
||||
* follow the rules for volatiles, as stated in
|
||||
* <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
|
||||
* Chapter 17 of
|
||||
* <cite>The Java™ Language Specification</cite></a>:
|
||||
* <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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
203
jdk/test/java/util/concurrent/tck/AtomicBoolean9Test.java
Normal file
203
jdk/test/java/util/concurrent/tck/AtomicBoolean9Test.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
203
jdk/test/java/util/concurrent/tck/AtomicInteger9Test.java
Normal file
203
jdk/test/java/util/concurrent/tck/AtomicInteger9Test.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
267
jdk/test/java/util/concurrent/tck/AtomicIntegerArray9Test.java
Normal file
267
jdk/test/java/util/concurrent/tck/AtomicIntegerArray9Test.java
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
203
jdk/test/java/util/concurrent/tck/AtomicLong9Test.java
Normal file
203
jdk/test/java/util/concurrent/tck/AtomicLong9Test.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
266
jdk/test/java/util/concurrent/tck/AtomicLongArray9Test.java
Normal file
266
jdk/test/java/util/concurrent/tck/AtomicLongArray9Test.java
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
203
jdk/test/java/util/concurrent/tck/AtomicReference9Test.java
Normal file
203
jdk/test/java/util/concurrent/tck/AtomicReference9Test.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
266
jdk/test/java/util/concurrent/tck/AtomicReferenceArray9Test.java
Normal file
266
jdk/test/java/util/concurrent/tck/AtomicReferenceArray9Test.java
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -243,4 +243,5 @@ public class AtomicReferenceArrayTest extends JSR166TestCase {
|
||||
AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
|
||||
assertEquals(Arrays.toString(a), aa.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user