Java中的原子操作类

一:为什么需原子操作类

    当程序更新一个变量时,如果多个线程同时更新,那么我们可能得不到期望值。通常我们使用synchronized解决这个问题。

从JDK1.5开始,在java.util.concurrent.atomic 包的原子操作类提供了一种用法简单、高效、线程安全地更新一个变量的方式。

    类 AtomicBooleanAtomicIntegerAtomicLong 和 AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。


二:原子更新基本数据类型

AtomicBoolean

可以用原子方式更新的 boolean 值。

AtomicInteger

可以用原子方式更新的 int 值。

AtomicLong

扫描二维码关注公众号,回复: 122880 查看本文章

可以用原子方式更新的 long 值。

下面以AtomicInteger为例:

 int

addAndGet(int delta) 
  以原子方式将给定值与当前值相加。

 boolean

compareAndSet(int expect, int update) 
  如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

 int

decrementAndGet() 
  以原子方式将当前值减 1。

 int

get() 
  获取当前值。

 int

getAndAdd(int delta) 
  以原子方式将给定值与当前值相加。

 int

getAndDecrement() 
  以原子方式将当前值减 1。

 int

getAndIncrement() 
  以原子方式将当前值加 1。

 int

getAndSet(int newValue) 
  以原子方式设置为给定值,并返回旧值。

 int

incrementAndGet() 
  以原子方式将当前值加 1。

 int

intValue() 
  以 int 形式返回指定的数值。

    对于这些方法:i. addAndGet(1);    ->  ++i  

                            i. getAndAdd(1);     -> i++

            那么它们是如何实现原子操作的?

   public final boolean compareAndSet(int expect, int update) {

        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

}

        因为compareAndSwapInt的源码无法追到,我们采用分析的方式来解释CAS算法的逻辑。

    多线程并发的情况下,如果this值与expect值相等,则将update值赋值给this,更新成功返回true。若this值与expect值不相等,则说另一个线程已经访问并修改了值,则返回false,说明更新失败。

            代码没有加锁,那么另一个线程是如何得知值已经被修改了?

       private volatile int value;

        volatile修饰的变量,多线程间可见。一个线程修改了value值,其它正在访问value的线程也得到通知(value值已经被更改,值可见)。

 

三:原子跟新数组

AtomicIntegerArray

可以用原子方式更新其元素的 int 数组。

AtomicLongArray

可以用原子方式更新其元素的 long 数组。

AtomicReferenceArray<E>

可以用原子方式更新其元素的对象引用数组。

AtomicIntegerArray为例

构造函数

AtomicIntegerArray(int length) 
  创建给定长度的新 AtomicIntegerArray。

AtomicIntegerArray(int[] array) 
  创建与给定数组具有相同长度的新 AtomicIntegerArray,并从给定数组复制其所有元素。

   public AtomicIntegerArray(int[] array) {

        // Visibility guaranteed by final field guarantees

        this.array = array.clone();

    }

源代码分析:数组通过构造方法传递进去,然后AtomicIntegerArray会将传入的数组复制一份。所以AtomicIntegerArray对内部的元素进行操作时,不会影响传入的数组。


四:更新引用类型的数据

AtomicMarkableReference<V>

AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。

AtomicReference<V>

可以用原子方式更新的对象引用。

AtomicStampedReference<V>

AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。

    AtomicReference也实现了compareAndSet方法进行原子操作。

boolean

compareAndSet(V expect, V update) 
          如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

 

五:原子更新字段类

AtomicIntegerFieldUpdater<T>

基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。

AtomicLongFieldUpdater<T>

基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新

AtomicReferenceFieldUpdater<T,V>

基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。

①原子更新字段类都是抽象类,每次使用都必须使用静态方法newUpdater()创建一个更新器,并且设置想要更新的类和属性。

②更新类的字段必须使用public volatile修饰符。

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/sugar_map/article/details/79756429
今日推荐