除了基本类型有原子封装类外,任意引用类型也可以通过原子引用进行原子操作
该类的方法有:
get
public final V get()
获取当前值。
- 结果
当前值
set
public final void set(V newValue)
设置为给定值。
- 参数
newValue
- 新价值
lazySet
public final void lazySet(V newValue)
最终设定为给定值。
- 参数
newValue
- 新价值
- 从以下版本开始:
1.6
compareAndSet
public final boolean compareAndSet(V expect, V update)
如果当前值
==
为预期值,则将值设置为给定的更新值。
- 参数
expect
- 预期值
update
- 新的价值
- 结果
true
如果成功。 False return表示实际值不等于预期值。
weakCompareAndSet
public final boolean weakCompareAndSet(V expect, V update)
如果当前值为
==
的预期值,则将该值原子设置为给定的更新值。May fail spuriously and does not provide ordering guarantees ,所以只是很少适合替代
compareAndSet
。
- 参数
expect
- 预期值
update
- 新的价值
- 结果
true
如果成功
getAndSet
public final V getAndSet(V newValue)
将原子设置为给定值并返回旧值。
- 参数
newValue
- 新值
- 结果
以前的值
updateAndGet
public final V updateAndGet(UnaryOperator<V> updateFunction)
使用给定函数的结果原子更新当前值,返回更新的值。 该功能应该是无副作用的,因为尝试的更新由于线程之间的争用而失败时可能会被重新应用。
- 参数
updateFunction
- 无副作用的功能
- 结果
更新的值
- 从以下版本开始:
1.8
getAndAccumulate
public final V getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction)
使用给定函数应用给当前值和给定值的结果原子更新当前值,返回上一个值。 该功能应该是无副作用的,因为尝试的更新由于线程之间的争用而失败时可能会被重新应用。 该函数应用当前值作为其第一个参数,给定的更新作为第二个参数。
- 参数
x
- 更新值
accumulatorFunction
- 两个参数的无副作用的函数
- 结果
以前的值
- 从以下版本开始:
1.8
accumulateAndGet
public final V accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction)
使用将给定函数应用于当前值和给定值的结果原子更新当前值,返回更新后的值。 该功能应该是无副作用的,因为尝试的更新由于线程之间的争用而失败时可能会被重新应用。 该函数应用当前值作为其第一个参数,给定的更新作为第二个参数。
- 参数
x
- 更新值
accumulatorFunction
- 两个参数的无副作用函数
- 结果
更新的值
- 从以下版本开始:
1.8
拓展
-
ABA 问题的解决
- ABA Demo
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; public class ABADemo { static AtomicReference<Integer> atomicInt = new AtomicReference<>(100); public static void main(String[] args) { new Thread(() -> { atomicInt.compareAndSet(100, 101); atomicInt.compareAndSet(101, 100); }, "t1").start(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInt.compareAndSet(100, 111) + " " + atomicInt.get()); }, "t2").start(); } }
- 使用AtomicStampReference解决问题
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicStampedReference; public class ABADemo { static AtomicStampedReference<Integer> atomicInt = new AtomicStampedReference<>(100, 1); public static void main(String[] args) { new Thread(() -> { atomicInt.compareAndSet(100, 101, atomicInt.getStamp(), atomicInt.getStamp()+1); atomicInt.compareAndSet(101, 100, atomicInt.getStamp(), atomicInt.getStamp()+1); }, "t1").start(); new Thread(() -> { int stamp = atomicInt.getReference(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInt.compareAndSet(100, 111, stamp, stamp+1) + " " + atomicInt.getReference() + " 当前版本" + atomicInt.getStamp()); }, "t2").start(); } }
思考:AtomicStampedReference 相比较 AtomicReference 相当于“故技重施”,把CAS机制再次使用,加了一个Stamp变量