读《Java并发编程的艺术》学习笔记(七)

第7章  Java中的13个原子操作类

  当一个线程更新一个变量时,程序如果没有正确的同步,那么这个变量对于其他线程来说是不可见的。我们通常使用synchronized或者volatile来保证线程安全的更新共享变量。在JDK1.5中,提供了java.util.concurrent.atomic包,这个包中的原子操作类提供了一种用法简单,性能高效,线程安全地更新一个变量的方式。 

        Atomic包里一共提供了13个类,有4种类型的原子更新方式:原子更新基本类型、原子更新数组、原子更新引用和原子更新属性。其实现基本都是使用Unsafe实现的包装类。 

7.1  原子更新基本类型类 
        - AtomicBoolean:原子更新布尔类型 

        - AtomicInteger:原子更新整型 

        - AtomicLong:原子更新长整型 

        以上3个类提供的方法基本一致,我们以AtomicInteger为例进行分析。 

    AtomicInteger常用的方法有: 

        - int addAndGet(int delta):以原子方式将输入的数值与实例中的值相加,并返回结果。 

        - boolean compareAndSet(int expect,int upate):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。 

        - int getAndIncrement():以原子方式将当前值加1,返回自增前的值。 

        - void lazySet(int newValue):最终会设置成new Value,但可能导致其他线程在之后的一小段时间内还是可以读到旧的值。 

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

    其实现依靠我们熟悉的CAS算法: 

  在Java的基本类型中除了Atomic包中提供原子更新的基本类型外,还由char、float和double。那么这些在Atomic包中没有提供原子更新的基本类型怎么保证其原子更新呢? 

        从AtomicBoolean源码中我们可以得到答案:首先将Boolean转换为整型,然后使用comareAndSwapInt进行CAS,所以原子更新char、float、double同样可以以此实现。

7.2  原子更新数组 
        - AtomicIntegerArray:原子更新整型数组里的元素。 

        - AtomicLongArray:原子更新长整型数组里的元素。 

        - AtomicReferenceArray:原子更新引用类型数组里的元素。 

    【备注:】看书上说原子更新数组有4个类,除了上述3个外,还有AtomicBooleanArray类,但我在jdk5/6/7/8中都没有找到这个类的存在,只找到共12个原子操作类,而不是标题中的13个。不知道是否是书中的错误?请知情的童鞋不吝赐教。

    AtomicIntegerArray类主要提供原子的方式更新数组里的整型,其常用方法如下: 

        - int addAndGet(int i,int delta):以原子方式将输入值与数组中索引i的元素相加。 

        - boolean compareAndSet(int i,int expect,int update):如果当前值等于预期值,就把索引i的元素设置成update值。 

【备注】:在AtomicIntegerArray构造方法中,AtomicIntegerArray会将数组复制一份,所以当其对内数组元素进行修改时,不会影响原传入数组。 

7.3  原子更新引用类型 
        原子更新基本类型的AtomicInteger,只能更新一个变量,如果需要原子更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic包提供以下3个类: 

        - AtomicReference:原子更新引用变量。 

        - AtomicReferenceFieldUpdater:原子更新引用类型里的字段。 

        - AtomicMarkableReference:原子更新带有标记位的引用类型 。可以原子更新一个布尔类型的标记位和引用类型。构造方法时AtomicMarkableReference(V initialRef,boolean initialMark)。

7.4  原子更新字段类 
        如果需要原子的更新某个类里的某个字段,就需要使用原子更新字段类,Atomic包提供了以下3个类进行原子字段更新: 

        - AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。 

        - AtomicLongFiledUpdater:原子更新长整型字段的更新器。 

        - AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,用于原子的更新数据和数据的版本号,避免CAS的ABA问题、 

        想要原子的更新字段类需要调用静态方法newUpdater()创建一个更新器,并设置想要更新的类和属性。且更新类的字段必须使用public volatile修饰符。

原文地址:https://www.cnblogs.com/mYunYu/p/12973059.html