From 26cdda465c91f2ffc84d080f3cc4170fedcaa26f Mon Sep 17 00:00:00 2001 From: dl Date: Wed, 16 Jan 2013 12:09:35 +0000 Subject: [PATCH] 8001666: Add lambda-compatible atomics and accumulators to the ActomicXXX classes Reviewed-by: dl, chegar, darcy, goetz Contributed-by: dl@cs.oswego.edu, chris.hegarty@oracle.com --- .../util/concurrent/atomic/AtomicInteger.java | 88 +++++++++++++++++ .../concurrent/atomic/AtomicIntegerArray.java | 96 +++++++++++++++++++ .../atomic/AtomicIntegerFieldUpdater.java | 92 ++++++++++++++++++ .../util/concurrent/atomic/AtomicLong.java | 88 +++++++++++++++++ .../concurrent/atomic/AtomicLongArray.java | 96 +++++++++++++++++++ .../atomic/AtomicLongFieldUpdater.java | 92 ++++++++++++++++++ .../concurrent/atomic/AtomicReference.java | 88 +++++++++++++++++ .../atomic/AtomicReferenceArray.java | 96 +++++++++++++++++++ .../atomic/AtomicReferenceFieldUpdater.java | 92 ++++++++++++++++++ 9 files changed, 828 insertions(+) diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java b/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java index f1c76b02b..b48ef72df 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; /** @@ -203,6 +205,92 @@ public class AtomicInteger extends Number implements java.io.Serializable { return getAndAdd(delta) + delta; } + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java index b5578ed93..6e4d226ba 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; /** @@ -245,6 +247,100 @@ public class AtomicIntegerArray implements java.io.Serializable { return getAndAdd(i, delta) + delta; } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(int i, IntUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(int i, IntUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(int i, int x, + IntBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(int i, int x, + IntBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + int prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index e2ae9c4f5..fcd5dd05f 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.IntUnaryOperator; +import java.util.function.IntBinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -264,6 +266,96 @@ public abstract class AtomicIntegerFieldUpdater { return next; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final int updateAndGet(T obj, IntUnaryOperator updateFunction) { + int prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsInt(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final int getAndAccumulate(T obj, int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final int accumulateAndGet(T obj, int x, + IntBinaryOperator accumulatorFunction) { + int prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsInt(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + /** * Standard hotspot implementation using intrinsics */ diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicLong.java b/src/share/classes/java/util/concurrent/atomic/AtomicLong.java index b38cf041f..2e58d29b2 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicLong.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLong.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; /** @@ -217,6 +219,92 @@ public class AtomicLong extends Number implements java.io.Serializable { return getAndAdd(delta) + delta; } + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java b/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java index 9651426c7..2536a9b8e 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; /** @@ -244,6 +246,100 @@ public class AtomicLongArray implements java.io.Serializable { return getAndAdd(i, delta) + delta; } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(int i, LongUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(int i, LongUnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(int i, int x, + LongBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(int i, int x, + LongBinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + long prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index a013680ce..a7672263a 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.LongUnaryOperator; +import java.util.function.LongBinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -267,6 +269,96 @@ public abstract class AtomicLongFieldUpdater { return next; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final long updateAndGet(T obj, LongUnaryOperator updateFunction) { + long prev, next; + do { + prev = get(obj); + next = updateFunction.operateAsLong(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final long getAndAccumulate(T obj, long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final long accumulateAndGet(T obj, long x, + LongBinaryOperator accumulatorFunction) { + long prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operateAsLong(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + private static class CASUpdater extends AtomicLongFieldUpdater { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicReference.java b/src/share/classes/java/util/concurrent/atomic/AtomicReference.java index 94c9edca5..95b88d127 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicReference.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReference.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import sun.misc.Unsafe; /** @@ -141,6 +143,92 @@ public class AtomicReference implements java.io.Serializable { return (V)unsafe.getAndSetObject(this, valueOffset, newValue); } + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final V getAndUpdate(UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(); + next = updateFunction.operate(prev); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value with the results of + * applying the given function, 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. + * + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final V updateAndGet(UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(); + next = updateFunction.operate(prev); + } while (!compareAndSet(prev, next)); + return next; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final V getAndAccumulate(V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(prev, next)); + return prev; + } + + /** + * Atomically updates the current value 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 + * updates fail due to contention among threads. The function + * is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final V accumulateAndGet(V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(prev, next)); + return next; + } + /** * Returns the String representation of the current value. * @return the String representation of the current value diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index 713086185..3e6ce9698 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -36,6 +36,8 @@ package java.util.concurrent.atomic; import java.util.Arrays; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import java.lang.reflect.Array; import sun.misc.Unsafe; @@ -199,6 +201,100 @@ public class AtomicReferenceArray implements java.io.Serializable { return compareAndSet(i, expect, update); } + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final E getAndUpdate(int i, UnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operate(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * Atomically updates the element at index {@code i} with the results + * of applying the given function, 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. + * + * @param i the index + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final E updateAndGet(int i, UnaryOperator updateFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = updateFunction.operate(prev); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final E getAndAccumulate(int i, E x, + BinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return prev; + } + + /** + * 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 + * 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. + * + * @param i the index + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final E accumulateAndGet(int i, E x, + BinaryOperator accumulatorFunction) { + long offset = checkedByteOffset(i); + E prev, next; + do { + prev = getRaw(offset); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSetRaw(offset, prev, next)); + return next; + } + /** * Returns the String representation of the current values of array. * @return the String representation of the current values of array diff --git a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index 78c636956..a92d914ff 100644 --- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -34,6 +34,8 @@ */ package java.util.concurrent.atomic; +import java.util.function.UnaryOperator; +import java.util.function.BinaryOperator; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -183,6 +185,96 @@ public abstract class AtomicReferenceFieldUpdater { return prev; } + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the previous value + * @since 1.8 + */ + public final V getAndUpdate(T obj, UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(obj); + next = updateFunction.operate(prev); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this updater + * with the results of applying the given function, 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. + * + * @param obj An object whose field to get and set + * @param updateFunction a side-effect-free function + * @return the updated value + * @since 1.8 + */ + public final V updateAndGet(T obj, UnaryOperator updateFunction) { + V prev, next; + do { + prev = get(obj); + next = updateFunction.operate(prev); + } while (!compareAndSet(obj, prev, next)); + return next; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the previous value + * @since 1.8 + */ + public final V getAndAccumulate(T obj, V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(obj, prev, next)); + return prev; + } + + /** + * Atomically updates the field of the given object managed by this + * updater 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 updates fail due to contention among threads. The + * function is applied with the current value as its first argument, + * and the given update as the second argument. + * + * @param obj An object whose field to get and set + * @param x the update value + * @param accumulatorFunction a side-effect-free function of two arguments + * @return the updated value + * @since 1.8 + */ + public final V accumulateAndGet(T obj, V x, + BinaryOperator accumulatorFunction) { + V prev, next; + do { + prev = get(obj); + next = accumulatorFunction.operate(prev, x); + } while (!compareAndSet(obj, prev, next)); + return next; + } + private static final class AtomicReferenceFieldUpdaterImpl extends AtomicReferenceFieldUpdater { private static final Unsafe unsafe = Unsafe.getUnsafe(); -- GitLab