Atomic原子类总结

Atomic 原子类介绍

Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

所以,所谓原子类说简单点就是具有原子/原子操作特征的类。

并发包 java.util.concurrent 的原子类都存放在java.util.concurrent.atomic下,如下图所示。

 

根据操作的数据类型,可以将 JUC 包中的原子类分为 4 类

基本类型

使用原子的方式更新基本类型

  • AtomicInteger:整型原子类
  • AtomicLong:长整型原子类
  • AtomicBoolean :布尔型原子类

数组类型

使用原子的方式更新数组里的某个元素

  • AtomicIntegerArray:整型数组原子类
  • AtomicLongArray:长整型数组原子类
  • AtomicReferenceArray :引用类型数组原子类

引用类型

  • AtomicReference:引用类型原子类
  • AtomicMarkableReference:原子更新带有标记的引用类型。该类将 boolean 标记与引用关联起来,也可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
  • AtomicStampedReference :原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。

对象的属性修改类型

  • AtomicIntegerFieldUpdater:原子更新整型字段的更新器
  • AtomicLongFieldUpdater:原子更新长整型字段的更新器
  • AtomicReferenceFieldUpdater:原子更新引用类型里的字段

 

 

一、基本类型原子类

使用原子的方式更新基本类型

  • AtomicInteger:整型原子类
  • AtomicLong:长整型原子类
  • AtomicBoolean :布尔型原子类

上面三个类提供的方法几乎相同,所以我们这里以 AtomicInteger 为例子来介绍。

 

1.1 AtomicInteger 类常用方法

1 public final int get() //获取当前的值
2 public final int getAndSet(int newValue)//获取当前的值,并设置新的值
3 public final int getAndIncrement()//获取当前的值,并自增
4 public final int getAndDecrement() //获取当前的值,并自减
5 public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
6 boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)
7 public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。

 

1.2 AtomicInteger 常见方法使用

 1 import java.util.concurrent.atomic.AtomicInteger;
 2 
 3 public class AtomicIntegerTest {
 4 
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7         int temvalue = 0;
 8         AtomicInteger i = new AtomicInteger(0);
 9         temvalue = i.getAndSet(3);
10         System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:0;  i:3
11         temvalue = i.getAndIncrement();
12         System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:3;  i:4
13         temvalue = i.getAndAdd(5);
14         System.out.println("temvalue:" + temvalue + ";  i:" + i);//temvalue:4;  i:9
15     }
16 }

 

1.3 基本数据类型原子类的优势

通过一个简单例子带大家看一下基本数据类型原子类的优势

① 多线程环境不使用原子类保证线程安全(基本数据类型)

 1 class Test {
 2     private volatile int count = 0;
 3     //若要线程安全执行执行count++,需要加锁
 4     public synchronized void increment() {
 5         count++;
 6     }
 7 
 8     public int getCount() {
 9         return count;
10     }
11 }

② 多线程环境使用原子类保证线程安全(基本数据类型)

 1 class Test2 {
 2     private AtomicInteger count = new AtomicInteger();
 3 
 4     public void increment() {
 5         count.incrementAndGet();
 6     }
 7     //使用AtomicInteger之后,不需要加锁,也可以实现线程安全。
 8     public int getCount() {
 9         return count.get();
10     }
11 }

 

1.4 AtomicInteger 线程安全原理简单分析

AtomicInteger 类的部分源码

 1     // setup to use Unsafe.compareAndSwapInt for updates(更新操作时提供“比较并替换”的作用)
 2     private static final Unsafe unsafe = Unsafe.getUnsafe();
 3     private static final long valueOffset;
 4 
 5     static {
 6         try {
 7             valueOffset = unsafe.objectFieldOffset
 8                     (AtomicInteger.class.getDeclaredField("value"));
 9         } catch (Exception ex) { throw new Error(ex); }
10     }
11 
12     private volatile int value;

AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。

CAS 的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个 volatile 变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。

 

 

二、数组类型原子类

使用原子的方式更新数组里的某个元素

  • AtomicIntegerArray:整形数组原子类
  • AtomicLongArray:长整形数组原子类
  • AtomicReferenceArray :引用类型数组原子类

上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerArray 为例子来介绍。

 

2.1 AtomicIntegerArray 类常用方法 

1 public final int get(int i) //获取 index=i 位置元素的值
2 public final int getAndSet(int i, int newValue)//返回 index=i 位置的当前的值,并将其设置为新值:newValue
3 public final int getAndIncrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自增
4 public final int getAndDecrement(int i) //获取 index=i 位置元素的值,并让该位置的元素自减
5 public final int getAndAdd(int i, int delta) //获取 index=i 位置元素的值,并加上预期的值
6 boolean compareAndSet(int i, int expect, int update) //如果输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update)
7 public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。

 

2.2 AtomicIntegerArray 常见方法使用

 1 import java.util.concurrent.atomic.AtomicIntegerArray;
 2 
 3 public class AtomicIntegerArrayTest {
 4 
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7         int temvalue = 0;
 8         int[] nums = { 1, 2, 3, 4, 5, 6 };
 9         AtomicIntegerArray i = new AtomicIntegerArray(nums);
10         for (int j = 0; j < nums.length; j++) {
11             System.out.println(i.get(j));
12         }
13         temvalue = i.getAndSet(0, 2);
14         System.out.println("temvalue:" + temvalue + ";  i:" + i);
15         temvalue = i.getAndIncrement(0);
16         System.out.println("temvalue:" + temvalue + ";  i:" + i);
17         temvalue = i.getAndAdd(0, 5);
18         System.out.println("temvalue:" + temvalue + ";  i:" + i);
19     }
20 }

 

 

三、引用类型原子类

基本类型原子类只能更新一个变量,如果需要原子更新多个变量,需要使用 引用类型原子类。

  • AtomicReference:引用类型原子类
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
  • AtomicMarkableReference :原子更新带有标记的引用类型。该类将 boolean 标记与引用关联起来,也可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。

上面三个类提供的方法几乎相同,所以我们这里以 AtomicReference 为例子来介绍。

 

3.1 AtomicReference 类常用方法

  1 package java.util.concurrent.atomic;
  2 import java.util.function.UnaryOperator;
  3 import java.util.function.BinaryOperator;
  4 import sun.misc.Unsafe;
  5 
  6 /**
  7  * An object reference that may be updated atomically. See the {@link
  8  * java.util.concurrent.atomic} package specification for description
  9  * of the properties of atomic variables.
 10  * @since 1.5
 11  * @author Doug Lea
 12  * @param <V> The type of object referred to by this reference
 13  */
 14 public class AtomicReference<V> implements java.io.Serializable {
 15     private static final long serialVersionUID = -1848883965231344442L;
 16 
 17     private static final Unsafe unsafe = Unsafe.getUnsafe();
 18     private static final long valueOffset;
 19 
 20     static {
 21         try {
 22             valueOffset = unsafe.objectFieldOffset
 23                 (AtomicReference.class.getDeclaredField("value"));
 24         } catch (Exception ex) { throw new Error(ex); }
 25     }
 26 
 27     private volatile V value;
 28 
 29     /**
 30      * Creates a new AtomicReference with the given initial value.
 31      *
 32      * @param initialValue the initial value
 33      */
 34     public AtomicReference(V initialValue) {
 35         value = initialValue;
 36     }
 37 
 38     /**
 39      * Creates a new AtomicReference with null initial value.
 40      */
 41     public AtomicReference() {
 42     }
 43 
 44     /**
 45      * Gets the current value.
 46      *
 47      * @return the current value
 48      */
 49     public final V get() {
 50         return value;
 51     }
 52 
 53     /**
 54      * Sets to the given value.
 55      *
 56      * @param newValue the new value
 57      */
 58     public final void set(V newValue) {
 59         value = newValue;
 60     }
 61 
 62     /**
 63      * Eventually sets to the given value.
 64      *
 65      * @param newValue the new value
 66      * @since 1.6
 67      */
 68     public final void lazySet(V newValue) {
 69         unsafe.putOrderedObject(this, valueOffset, newValue);
 70     }
 71 
 72     /**
 73      * Atomically sets the value to the given updated value
 74      * if the current value {@code ==} the expected value.
 75      * @param expect the expected value
 76      * @param update the new value
 77      * @return {@code true} if successful. False return indicates that
 78      * the actual value was not equal to the expected value.
 79      */
 80     public final boolean compareAndSet(V expect, V update) {
 81         return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
 82     }
 83 
 84     /**
 85      * Atomically sets the value to the given updated value
 86      * if the current value {@code ==} the expected value.
 87      *
 88      * <p><a href="package-summary.html#weakCompareAndSet">May fail
 89      * spuriously and does not provide ordering guarantees</a>, so is
 90      * only rarely an appropriate alternative to {@code compareAndSet}.
 91      *
 92      * @param expect the expected value
 93      * @param update the new value
 94      * @return {@code true} if successful
 95      */
 96     public final boolean weakCompareAndSet(V expect, V update) {
 97         return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
 98     }
 99 
100     /**
101      * Atomically sets to the given value and returns the old value.
102      *
103      * @param newValue the new value
104      * @return the previous value
105      */
106     @SuppressWarnings("unchecked")
107     public final V getAndSet(V newValue) {
108         return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
109     }
110 
111     /**
112      * Atomically updates the current value with the results of
113      * applying the given function, returning the previous value. The
114      * function should be side-effect-free, since it may be re-applied
115      * when attempted updates fail due to contention among threads.
116      *
117      * @param updateFunction a side-effect-free function
118      * @return the previous value
119      * @since 1.8
120      */
121     public final V getAndUpdate(UnaryOperator<V> updateFunction) {
122         V prev, next;
123         do {
124             prev = get();
125             next = updateFunction.apply(prev);
126         } while (!compareAndSet(prev, next));
127         return prev;
128     }
129 
130     /**
131      * Atomically updates the current value with the results of
132      * applying the given function, returning the updated value. The
133      * function should be side-effect-free, since it may be re-applied
134      * when attempted updates fail due to contention among threads.
135      *
136      * @param updateFunction a side-effect-free function
137      * @return the updated value
138      * @since 1.8
139      */
140     public final V updateAndGet(UnaryOperator<V> updateFunction) {
141         V prev, next;
142         do {
143             prev = get();
144             next = updateFunction.apply(prev);
145         } while (!compareAndSet(prev, next));
146         return next;
147     }
148 
149     /**
150      * Atomically updates the current value with the results of
151      * applying the given function to the current and given values,
152      * returning the previous value. The function should be
153      * side-effect-free, since it may be re-applied when attempted
154      * updates fail due to contention among threads.  The function
155      * is applied with the current value as its first argument,
156      * and the given update as the second argument.
157      *
158      * @param x the update value
159      * @param accumulatorFunction a side-effect-free function of two arguments
160      * @return the previous value
161      * @since 1.8
162      */
163     public final V getAndAccumulate(V x,
164                                     BinaryOperator<V> accumulatorFunction) {
165         V prev, next;
166         do {
167             prev = get();
168             next = accumulatorFunction.apply(prev, x);
169         } while (!compareAndSet(prev, next));
170         return prev;
171     }
172 
173     /**
174      * Atomically updates the current value with the results of
175      * applying the given function to the current and given values,
176      * returning the updated value. The function should be
177      * side-effect-free, since it may be re-applied when attempted
178      * updates fail due to contention among threads.  The function
179      * is applied with the current value as its first argument,
180      * and the given update as the second argument.
181      *
182      * @param x the update value
183      * @param accumulatorFunction a side-effect-free function of two arguments
184      * @return the updated value
185      * @since 1.8
186      */
187     public final V accumulateAndGet(V x,
188                                     BinaryOperator<V> accumulatorFunction) {
189         V prev, next;
190         do {
191             prev = get();
192             next = accumulatorFunction.apply(prev, x);
193         } while (!compareAndSet(prev, next));
194         return next;
195     }
196 
197     /**
198      * Returns the String representation of the current value.
199      * @return the String representation of the current value
200      */
201     public String toString() {
202         return String.valueOf(get());
203     }
204 }
View Code

 

3.2 AtomicReference 类使用示例

 1 import java.util.concurrent.atomic.AtomicReference;
 2 
 3 public class AtomicReferenceTest {
 4     public static void main(String[] args) {
 5         AtomicReference<Person> ar = new AtomicReference<Person>();
 6         Person person = new Person("SnailClimb", 22);
 7         ar.set(person);
 8         Person updatePerson = new Person("Daisy", 20);
 9         ar.compareAndSet(person, updatePerson);
10 
11         System.out.println(ar.get().getName());
12         System.out.println(ar.get().getAge());
13     }
14 }
15 
16 class Person {
17     private String name;
18     private int age;
19 
20     public Person(String name, int age) {
21         super();
22         this.name = name;
23         this.age = age;
24     }
25 
26     public String getName() {
27         return name;
28     }
29 
30     public void setName(String name) {
31         this.name = name;
32     }
33 
34     public int getAge() {
35         return age;
36     }
37 
38     public void setAge(int age) {
39         this.age = age;
40     }
41 }

上述代码首先创建了一个 Person 对象,然后把 Person 对象设置进 AtomicReference 对象中,然后调用 compareAndSet 方法,该方法就是通过 CAS 操作设置 ar。如果 ar 的值为 person 的话,则将其设置为 updatePerson。实现原理与 AtomicInteger 类中的 compareAndSet 方法相同。运行上面的代码后的输出结果如下:

1 Daisy
2 20

 

3.3 AtomicStampedReference 常用方法

 1 package com.test.java;
 2 
 3 import java.util.concurrent.atomic.AtomicStampedReference;
 4 
 5 /**
 6  * @description:
 7  * @author: luguilin
 8  * @date: 2022-03-28 17:55
 9  **/
10 
11 public class AtomicStampedReferenceDemo {
12     public static void main(String[] args) {
13         // 实例化、取当前值和 stamp 值
14         final Integer initialRef = 0, initialStamp = 0;
15         final AtomicStampedReference<Integer> asr = new AtomicStampedReference<>(initialRef, initialStamp);
16         System.out.println("currentValue=" + asr.getReference() + ", currentStamp=" + asr.getStamp());
17 
18         // compare and set
19         final Integer newReference = 666, newStamp = 999;
20         final boolean casResult = asr.compareAndSet(initialRef, newReference, initialStamp, newStamp);
21         System.out.println("currentValue=" + asr.getReference()
22                 + ", currentStamp=" + asr.getStamp()
23                 + ", casResult=" + casResult);
24 
25         // 获取当前的值和当前的 stamp 值
26         int[] arr = new int[1];
27         final Integer currentValue = asr.get(arr);
28         final int currentStamp = arr[0];
29         System.out.println("currentValue=" + currentValue + ", currentStamp=" + currentStamp);
30 
31         // 单独设置 stamp 值
32         final boolean attemptStampResult = asr.attemptStamp(newReference, 88);
33         System.out.println("currentValue=" + asr.getReference()
34                 + ", currentStamp=" + asr.getStamp()
35                 + ", attemptStampResult=" + attemptStampResult);
36 
37         // 重新设置当前值和 stamp 值
38         asr.set(initialRef, initialStamp);
39         System.out.println("currentValue=" + asr.getReference() + ", currentStamp=" + asr.getStamp());
40 
41         // [不推荐使用,除非搞清楚注释的意思了] weak compare and set
42         // 困惑!weakCompareAndSet 这个方法最终还是调用 compareAndSet 方法。[版本: jdk-8u191]
43         // 但是注释上写着 "May fail spuriously and does not provide ordering guarantees,
44         // so is only rarely an appropriate alternative to compareAndSet."
45         // todo 感觉有可能是 jvm 通过方法名在 native 方法里面做了转发
46         final boolean wCasResult = asr.weakCompareAndSet(initialRef, newReference, initialStamp, newStamp);
47         System.out.println("currentValue=" + asr.getReference()
48                 + ", currentStamp=" + asr.getStamp()
49                 + ", wCasResult=" + wCasResult);
50     }
51 }
View Code

 

3.4 AtomicStampedReference 类使用示例

 1 package com.test.java;
 2 
 3 import java.util.concurrent.atomic.AtomicStampedReference;
 4 
 5 /**
 6  * @description:
 7  * @author: luguilin
 8  * @date: 2022-03-28 17:55
 9  **/
10 
11 public class AtomicStampedReferenceDemo {
12     public static void main(String[] args) {
13         // 实例化、取当前值和 stamp 值
14         final Integer initialRef = 0, initialStamp = 0;
15         final AtomicStampedReference<Integer> asr = new AtomicStampedReference<>(initialRef, initialStamp);
16         System.out.println("currentValue=" + asr.getReference() + ", currentStamp=" + asr.getStamp());
17 
18         // compare and set
19         final Integer newReference = 666, newStamp = 999;
20         final boolean casResult = asr.compareAndSet(initialRef, newReference, initialStamp, newStamp);
21         System.out.println("currentValue=" + asr.getReference()
22                 + ", currentStamp=" + asr.getStamp()
23                 + ", casResult=" + casResult);
24 
25         // 获取当前的值和当前的 stamp 值
26         int[] arr = new int[1];
27         final Integer currentValue = asr.get(arr);
28         final int currentStamp = arr[0];
29         System.out.println("currentValue=" + currentValue + ", currentStamp=" + currentStamp);
30 
31         // 单独设置 stamp 值
32         final boolean attemptStampResult = asr.attemptStamp(newReference, 88);
33         System.out.println("currentValue=" + asr.getReference()
34                 + ", currentStamp=" + asr.getStamp()
35                 + ", attemptStampResult=" + attemptStampResult);
36 
37         // 重新设置当前值和 stamp 值
38         asr.set(initialRef, initialStamp);
39         System.out.println("currentValue=" + asr.getReference() + ", currentStamp=" + asr.getStamp());
40 
41         // [不推荐使用,除非搞清楚注释的意思了] weak compare and set
42         // 困惑!weakCompareAndSet 这个方法最终还是调用 compareAndSet 方法。[版本: jdk-8u191]
43         // 但是注释上写着 "May fail spuriously and does not provide ordering guarantees,
44         // so is only rarely an appropriate alternative to compareAndSet."
45         // todo 感觉有可能是 jvm 通过方法名在 native 方法里面做了转发
46         final boolean wCasResult = asr.weakCompareAndSet(initialRef, newReference, initialStamp, newStamp);
47         System.out.println("currentValue=" + asr.getReference()
48                 + ", currentStamp=" + asr.getStamp()
49                 + ", wCasResult=" + wCasResult);
50     }
51 }

输出结果如下:

1 currentValue=0, currentStamp=0
2 currentValue=666, currentStamp=999, casResult=true
3 currentValue=666, currentStamp=999
4 currentValue=666, currentStamp=88, attemptStampResult=true
5 currentValue=0, currentStamp=0
6 currentValue=666, currentStamp=999, wCasResult=true

 

3.5 AtomicMarkableReference 常用方法

  1 package java.util.concurrent.atomic;
  2 
  3 /**
  4  * An {@code AtomicMarkableReference} maintains an object reference
  5  * along with a mark bit, that can be updated atomically.
  6  *
  7  * <p>Implementation note: This implementation maintains markable
  8  * references by creating internal objects representing "boxed"
  9  * [reference, boolean] pairs.
 10  *
 11  * @since 1.5
 12  * @author Doug Lea
 13  * @param <V> The type of object referred to by this reference
 14  */
 15 public class AtomicMarkableReference<V> {
 16 
 17     private static class Pair<T> {
 18         final T reference;
 19         final boolean mark;
 20         private Pair(T reference, boolean mark) {
 21             this.reference = reference;
 22             this.mark = mark;
 23         }
 24         static <T> Pair<T> of(T reference, boolean mark) {
 25             return new Pair<T>(reference, mark);
 26         }
 27     }
 28 
 29     private volatile Pair<V> pair;
 30 
 31     /**
 32      * Creates a new {@code AtomicMarkableReference} with the given
 33      * initial values.
 34      *
 35      * @param initialRef the initial reference
 36      * @param initialMark the initial mark
 37      */
 38     public AtomicMarkableReference(V initialRef, boolean initialMark) {
 39         pair = Pair.of(initialRef, initialMark);
 40     }
 41 
 42     /**
 43      * Returns the current value of the reference.
 44      *
 45      * @return the current value of the reference
 46      */
 47     public V getReference() {
 48         return pair.reference;
 49     }
 50 
 51     /**
 52      * Returns the current value of the mark.
 53      *
 54      * @return the current value of the mark
 55      */
 56     public boolean isMarked() {
 57         return pair.mark;
 58     }
 59 
 60     /**
 61      * Returns the current values of both the reference and the mark.
 62      * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
 63      *
 64      * @param markHolder an array of size of at least one. On return,
 65      * {@code markholder[0]} will hold the value of the mark.
 66      * @return the current value of the reference
 67      */
 68     public V get(boolean[] markHolder) {
 69         Pair<V> pair = this.pair;
 70         markHolder[0] = pair.mark;
 71         return pair.reference;
 72     }
 73 
 74     /**
 75      * Atomically sets the value of both the reference and mark
 76      * to the given update values if the
 77      * current reference is {@code ==} to the expected reference
 78      * and the current mark is equal to the expected mark.
 79      *
 80      * <p><a href="package-summary.html#weakCompareAndSet">May fail
 81      * spuriously and does not provide ordering guarantees</a>, so is
 82      * only rarely an appropriate alternative to {@code compareAndSet}.
 83      *
 84      * @param expectedReference the expected value of the reference
 85      * @param newReference the new value for the reference
 86      * @param expectedMark the expected value of the mark
 87      * @param newMark the new value for the mark
 88      * @return {@code true} if successful
 89      */
 90     public boolean weakCompareAndSet(V       expectedReference,
 91                                      V       newReference,
 92                                      boolean expectedMark,
 93                                      boolean newMark) {
 94         return compareAndSet(expectedReference, newReference,
 95                              expectedMark, newMark);
 96     }
 97 
 98     /**
 99      * Atomically sets the value of both the reference and mark
100      * to the given update values if the
101      * current reference is {@code ==} to the expected reference
102      * and the current mark is equal to the expected mark.
103      *
104      * @param expectedReference the expected value of the reference
105      * @param newReference the new value for the reference
106      * @param expectedMark the expected value of the mark
107      * @param newMark the new value for the mark
108      * @return {@code true} if successful
109      */
110     public boolean compareAndSet(V       expectedReference,
111                                  V       newReference,
112                                  boolean expectedMark,
113                                  boolean newMark) {
114         Pair<V> current = pair;
115         return
116             expectedReference == current.reference &&
117             expectedMark == current.mark &&
118             ((newReference == current.reference &&
119               newMark == current.mark) ||
120              casPair(current, Pair.of(newReference, newMark)));
121     }
122 
123     /**
124      * Unconditionally sets the value of both the reference and mark.
125      *
126      * @param newReference the new value for the reference
127      * @param newMark the new value for the mark
128      */
129     public void set(V newReference, boolean newMark) {
130         Pair<V> current = pair;
131         if (newReference != current.reference || newMark != current.mark)
132             this.pair = Pair.of(newReference, newMark);
133     }
134 
135     /**
136      * Atomically sets the value of the mark to the given update value
137      * if the current reference is {@code ==} to the expected
138      * reference.  Any given invocation of this operation may fail
139      * (return {@code false}) spuriously, but repeated invocation
140      * when the current value holds the expected value and no other
141      * thread is also attempting to set the value will eventually
142      * succeed.
143      *
144      * @param expectedReference the expected value of the reference
145      * @param newMark the new value for the mark
146      * @return {@code true} if successful
147      */
148     public boolean attemptMark(V expectedReference, boolean newMark) {
149         Pair<V> current = pair;
150         return
151             expectedReference == current.reference &&
152             (newMark == current.mark ||
153              casPair(current, Pair.of(expectedReference, newMark)));
154     }
155 
156     // Unsafe mechanics
157 
158     private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
159     private static final long pairOffset =
160         objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
161 
162     private boolean casPair(Pair<V> cmp, Pair<V> val) {
163         return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
164     }
165 
166     static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
167                                   String field, Class<?> klazz) {
168         try {
169             return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
170         } catch (NoSuchFieldException e) {
171             // Convert Exception to corresponding Error
172             NoSuchFieldError error = new NoSuchFieldError(field);
173             error.initCause(e);
174             throw error;
175         }
176     }
177 }
View Code

3.6 AtomicMarkableReference 类使用示例

 1 import java.util.concurrent.atomic.AtomicMarkableReference;
 2 
 3 public class AtomicMarkableReferenceDemo {
 4     public static void main(String[] args) {
 5         // 实例化、取当前值和 mark 值
 6         final Boolean initialRef = null, initialMark = false;
 7         final AtomicMarkableReference<Boolean> amr = new AtomicMarkableReference<>(initialRef, initialMark);
 8         System.out.println("currentValue=" + amr.getReference() + ", currentMark=" + amr.isMarked());
 9 
10         // compare and set
11         final Boolean newReference1 = true, newMark1 = true;
12         final boolean casResult = amr.compareAndSet(initialRef, newReference1, initialMark, newMark1);
13         System.out.println("currentValue=" + amr.getReference()
14                 + ", currentMark=" + amr.isMarked()
15                 + ", casResult=" + casResult);
16 
17         // 获取当前的值和当前的 mark 值
18         boolean[] arr = new boolean[1];
19         final Boolean currentValue = amr.get(arr);
20         final boolean currentMark = arr[0];
21         System.out.println("currentValue=" + currentValue + ", currentMark=" + currentMark);
22 
23         // 单独设置 mark 值
24         final boolean attemptMarkResult = amr.attemptMark(newReference1, false);
25         System.out.println("currentValue=" + amr.getReference()
26                 + ", currentMark=" + amr.isMarked()
27                 + ", attemptMarkResult=" + attemptMarkResult);
28 
29         // 重新设置当前值和 mark 值
30         amr.set(initialRef, initialMark);
31         System.out.println("currentValue=" + amr.getReference() + ", currentMark=" + amr.isMarked());
32 
33         // [不推荐使用,除非搞清楚注释的意思了] weak compare and set
34         // 困惑!weakCompareAndSet 这个方法最终还是调用 compareAndSet 方法。[版本: jdk-8u191]
35         // 但是注释上写着 "May fail spuriously and does not provide ordering guarantees,
36         // so is only rarely an appropriate alternative to compareAndSet."
37         // todo 感觉有可能是 jvm 通过方法名在 native 方法里面做了转发
38         final boolean wCasResult = amr.weakCompareAndSet(initialRef, newReference1, initialMark, newMark1);
39         System.out.println("currentValue=" + amr.getReference()
40                 + ", currentMark=" + amr.isMarked()
41                 + ", wCasResult=" + wCasResult);
42     }
43 }

输出结果如下:

1 currentValue=null, currentMark=false
2 currentValue=true, currentMark=true, casResult=true
3 currentValue=true, currentMark=true
4 currentValue=true, currentMark=false, attemptMarkResult=true
5 currentValue=null, currentMark=false
6 currentValue=true, currentMark=true, wCasResult=true

 

3.7 解决 CAS ABA 问题

AtomicMarkableReference是将一个boolean值作是否有更改的标记,本质就是它的版本号只有两个,true和false,

修改的时候在这两个版本号之间来回切换,这样做并不能解决ABA的问题,只是会降低ABA问题发生的几率而已

例如

 1 public class SolveABAByAtomicMarkableReference {
 2 
 3     private static AtomicMarkableReference atomicMarkableReference = new AtomicMarkableReference(100, false);
 4 
 5     public static void main(String[] args) {
 6 
 7         Thread refT1 = new Thread(() -> {
 8             try {
 9                 TimeUnit.SECONDS.sleep(1);
10             } catch (InterruptedException e) {
11                 e.printStackTrace();
12             }
13             atomicMarkableReference.compareAndSet(100, 101, atomicMarkableReference.isMarked(), !atomicMarkableReference.isMarked());
14             atomicMarkableReference.compareAndSet(101, 100, atomicMarkableReference.isMarked(), !atomicMarkableReference.isMarked());
15         });
16 
17         Thread refT2 = new Thread(() -> {
18             boolean marked = atomicMarkableReference.isMarked();
19             try {
20                 TimeUnit.SECONDS.sleep(2);
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24             boolean c3 = atomicMarkableReference.compareAndSet(100, 101, marked, !marked);
25             System.out.println(c3); // 返回true,实际应该返回false
26         });
27 
28         refT1.start();
29         refT2.start();
30     }
31 }

CAS ABA 问题

  • 描述: 第一个线程取到了变量 x 的值 A,然后巴拉巴拉干别的事,总之就是只拿到了变量 x 的值 A。这段时间内第二个线程也取到了变量 x 的值 A,然后把变量 x 的值改为 B,然后巴拉巴拉干别的事,最后又把变量 x 的值变为 A (相当于还原了)。在这之后第一个线程终于进行了变量 x 的操作,但是此时变量 x 的值还是 A,所以 compareAndSet 操作是成功。
  • 例子描述(可能不太合适,但好理解): 年初,现金为零,然后通过正常劳动赚了三百万,之后正常消费了(比如买房子)三百万。年末,虽然现金零收入(可能变成其他形式了),但是赚了钱是事实,还是得交税的!
  • 代码例子(以AtomicInteger为例)
 1 import java.util.concurrent.atomic.AtomicInteger;
 2 
 3 public class AtomicIntegerDefectDemo {
 4     public static void main(String[] args) {
 5         defectOfABA();
 6     }
 7 
 8     static void defectOfABA() {
 9         final AtomicInteger atomicInteger = new AtomicInteger(1);
10 
11         Thread coreThread = new Thread(
12                 () -> {
13                     final int currentValue = atomicInteger.get();
14                     System.out.println(Thread.currentThread().getName() + " ------ currentValue=" + currentValue);
15 
16                     // 这段目的:模拟处理其他业务花费的时间
17                     try {
18                         Thread.sleep(300);
19                     } catch (InterruptedException e) {
20                         e.printStackTrace();
21                     }
22 
23                     boolean casResult = atomicInteger.compareAndSet(1, 2);
24                     System.out.println(Thread.currentThread().getName()
25                             + " ------ currentValue=" + currentValue
26                             + ", finalValue=" + atomicInteger.get()
27                             + ", compareAndSet Result=" + casResult);
28                 }
29         );
30         coreThread.start();
31 
32         // 这段目的:为了让 coreThread 线程先跑起来
33         try {
34             Thread.sleep(100);
35         } catch (InterruptedException e) {
36             e.printStackTrace();
37         }
38 
39         Thread amateurThread = new Thread(
40                 () -> {
41                     int currentValue = atomicInteger.get();
42                     boolean casResult = atomicInteger.compareAndSet(1, 2);
43                     System.out.println(Thread.currentThread().getName()
44                             + " ------ currentValue=" + currentValue
45                             + ", finalValue=" + atomicInteger.get()
46                             + ", compareAndSet Result=" + casResult);
47 
48                     currentValue = atomicInteger.get();
49                     casResult = atomicInteger.compareAndSet(2, 1);
50                     System.out.println(Thread.currentThread().getName()
51                             + " ------ currentValue=" + currentValue
52                             + ", finalValue=" + atomicInteger.get()
53                             + ", compareAndSet Result=" + casResult);
54                 }
55         );
56         amateurThread.start();
57     }
58 }

输出内容如下:

1 Thread-0 ------ currentValue=1
2 Thread-1 ------ currentValue=1, finalValue=2, compareAndSet Result=true
3 Thread-1 ------ currentValue=2, finalValue=1, compareAndSet Result=true
4 Thread-0 ------ currentValue=1, finalValue=2, compareAndSet Result=true

 

 

四、对象的属性修改类型原子类

如果需要原子更新某个类里的某个字段时,需要用到对象的属性修改类型原子类。

  • AtomicIntegerFieldUpdater:原子更新整形字段的更新器
  • AtomicLongFieldUpdater:原子更新长整形字段的更新器
  • AtomicReferenceFieldUpdater :原子更新引用类型里的字段的更新器

要想原子地更新对象的属性需要两步。第一步,因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法 newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新的对象属性必须使用 public volatile 修饰符。

上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerFieldUpdater为例子来介绍。

 

4.1 AtomicIntegerFieldUpdater常用方法

  1 /*
  2  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  3  *
  4  *
  5  *
  6  *
  7  *
  8  *
  9  *
 10  *
 11  *
 12  *
 13  *
 14  *
 15  *
 16  *
 17  *
 18  *
 19  *
 20  *
 21  *
 22  *
 23  */
 24 
 25 /*
 26  *
 27  *
 28  *
 29  *
 30  *
 31  * Written by Doug Lea with assistance from members of JCP JSR-166
 32  * Expert Group and released to the public domain, as explained at
 33  * http://creativecommons.org/publicdomain/zero/1.0/
 34  */
 35 
 36 package java.util.concurrent.atomic;
 37 
 38 import java.lang.reflect.Field;
 39 import java.lang.reflect.Modifier;
 40 import java.security.AccessController;
 41 import java.security.PrivilegedActionException;
 42 import java.security.PrivilegedExceptionAction;
 43 import java.util.Objects;
 44 import java.util.function.IntBinaryOperator;
 45 import java.util.function.IntUnaryOperator;
 46 import sun.reflect.CallerSensitive;
 47 import sun.reflect.Reflection;
 48 
 49 /**
 50  * A reflection-based utility that enables atomic updates to
 51  * designated {@code volatile int} fields of designated classes.
 52  * This class is designed for use in atomic data structures in which
 53  * several fields of the same node are independently subject to atomic
 54  * updates.
 55  *
 56  * <p>Note that the guarantees of the {@code compareAndSet}
 57  * method in this class are weaker than in other atomic classes.
 58  * Because this class cannot ensure that all uses of the field
 59  * are appropriate for purposes of atomic access, it can
 60  * guarantee atomicity only with respect to other invocations of
 61  * {@code compareAndSet} and {@code set} on the same updater.
 62  *
 63  * @since 1.5
 64  * @author Doug Lea
 65  * @param <T> The type of the object holding the updatable field
 66  */
 67 public abstract class AtomicIntegerFieldUpdater<T> {
 68     /**
 69      * Creates and returns an updater for objects with the given field.
 70      * The Class argument is needed to check that reflective types and
 71      * generic types match.
 72      *
 73      * @param tclass the class of the objects holding the field
 74      * @param fieldName the name of the field to be updated
 75      * @param <U> the type of instances of tclass
 76      * @return the updater
 77      * @throws IllegalArgumentException if the field is not a
 78      * volatile integer type
 79      * @throws RuntimeException with a nested reflection-based
 80      * exception if the class does not hold field or is the wrong type,
 81      * or the field is inaccessible to the caller according to Java language
 82      * access control
 83      */
 84     @CallerSensitive
 85     public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
 86                                                               String fieldName) {
 87         return new AtomicIntegerFieldUpdaterImpl<U>
 88             (tclass, fieldName, Reflection.getCallerClass());
 89     }
 90 
 91     /**
 92      * Protected do-nothing constructor for use by subclasses.
 93      */
 94     protected AtomicIntegerFieldUpdater() {
 95     }
 96 
 97     /**
 98      * Atomically sets the field of the given object managed by this updater
 99      * to the given updated value if the current value {@code ==} the
100      * expected value. This method is guaranteed to be atomic with respect to
101      * other calls to {@code compareAndSet} and {@code set}, but not
102      * necessarily with respect to other changes in the field.
103      *
104      * @param obj An object whose field to conditionally set
105      * @param expect the expected value
106      * @param update the new value
107      * @return {@code true} if successful
108      * @throws ClassCastException if {@code obj} is not an instance
109      * of the class possessing the field established in the constructor
110      */
111     public abstract boolean compareAndSet(T obj, int expect, int update);
112 
113     /**
114      * Atomically sets the field of the given object managed by this updater
115      * to the given updated value if the current value {@code ==} the
116      * expected value. This method is guaranteed to be atomic with respect to
117      * other calls to {@code compareAndSet} and {@code set}, but not
118      * necessarily with respect to other changes in the field.
119      *
120      * <p><a href="package-summary.html#weakCompareAndSet">May fail
121      * spuriously and does not provide ordering guarantees</a>, so is
122      * only rarely an appropriate alternative to {@code compareAndSet}.
123      *
124      * @param obj An object whose field to conditionally set
125      * @param expect the expected value
126      * @param update the new value
127      * @return {@code true} if successful
128      * @throws ClassCastException if {@code obj} is not an instance
129      * of the class possessing the field established in the constructor
130      */
131     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
132 
133     /**
134      * Sets the field of the given object managed by this updater to the
135      * given updated value. This operation is guaranteed to act as a volatile
136      * store with respect to subsequent invocations of {@code compareAndSet}.
137      *
138      * @param obj An object whose field to set
139      * @param newValue the new value
140      */
141     public abstract void set(T obj, int newValue);
142 
143     /**
144      * Eventually sets the field of the given object managed by this
145      * updater to the given updated value.
146      *
147      * @param obj An object whose field to set
148      * @param newValue the new value
149      * @since 1.6
150      */
151     public abstract void lazySet(T obj, int newValue);
152 
153     /**
154      * Gets the current value held in the field of the given object managed
155      * by this updater.
156      *
157      * @param obj An object whose field to get
158      * @return the current value
159      */
160     public abstract int get(T obj);
161 
162     /**
163      * Atomically sets the field of the given object managed by this updater
164      * to the given value and returns the old value.
165      *
166      * @param obj An object whose field to get and set
167      * @param newValue the new value
168      * @return the previous value
169      */
170     public int getAndSet(T obj, int newValue) {
171         int prev;
172         do {
173             prev = get(obj);
174         } while (!compareAndSet(obj, prev, newValue));
175         return prev;
176     }
177 
178     /**
179      * Atomically increments by one the current value of the field of the
180      * given object managed by this updater.
181      *
182      * @param obj An object whose field to get and set
183      * @return the previous value
184      */
185     public int getAndIncrement(T obj) {
186         int prev, next;
187         do {
188             prev = get(obj);
189             next = prev + 1;
190         } while (!compareAndSet(obj, prev, next));
191         return prev;
192     }
193 
194     /**
195      * Atomically decrements by one the current value of the field of the
196      * given object managed by this updater.
197      *
198      * @param obj An object whose field to get and set
199      * @return the previous value
200      */
201     public int getAndDecrement(T obj) {
202         int prev, next;
203         do {
204             prev = get(obj);
205             next = prev - 1;
206         } while (!compareAndSet(obj, prev, next));
207         return prev;
208     }
209 
210     /**
211      * Atomically adds the given value to the current value of the field of
212      * the given object managed by this updater.
213      *
214      * @param obj An object whose field to get and set
215      * @param delta the value to add
216      * @return the previous value
217      */
218     public int getAndAdd(T obj, int delta) {
219         int prev, next;
220         do {
221             prev = get(obj);
222             next = prev + delta;
223         } while (!compareAndSet(obj, prev, next));
224         return prev;
225     }
226 
227     /**
228      * Atomically increments by one the current value of the field of the
229      * given object managed by this updater.
230      *
231      * @param obj An object whose field to get and set
232      * @return the updated value
233      */
234     public int incrementAndGet(T obj) {
235         int prev, next;
236         do {
237             prev = get(obj);
238             next = prev + 1;
239         } while (!compareAndSet(obj, prev, next));
240         return next;
241     }
242 
243     /**
244      * Atomically decrements by one the current value of the field of the
245      * given object managed by this updater.
246      *
247      * @param obj An object whose field to get and set
248      * @return the updated value
249      */
250     public int decrementAndGet(T obj) {
251         int prev, next;
252         do {
253             prev = get(obj);
254             next = prev - 1;
255         } while (!compareAndSet(obj, prev, next));
256         return next;
257     }
258 
259     /**
260      * Atomically adds the given value to the current value of the field of
261      * the given object managed by this updater.
262      *
263      * @param obj An object whose field to get and set
264      * @param delta the value to add
265      * @return the updated value
266      */
267     public int addAndGet(T obj, int delta) {
268         int prev, next;
269         do {
270             prev = get(obj);
271             next = prev + delta;
272         } while (!compareAndSet(obj, prev, next));
273         return next;
274     }
275 
276     /**
277      * Atomically updates the field of the given object managed by this updater
278      * with the results of applying the given function, returning the previous
279      * value. The function should be side-effect-free, since it may be
280      * re-applied when attempted updates fail due to contention among threads.
281      *
282      * @param obj An object whose field to get and set
283      * @param updateFunction a side-effect-free function
284      * @return the previous value
285      * @since 1.8
286      */
287     public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
288         int prev, next;
289         do {
290             prev = get(obj);
291             next = updateFunction.applyAsInt(prev);
292         } while (!compareAndSet(obj, prev, next));
293         return prev;
294     }
295 
296     /**
297      * Atomically updates the field of the given object managed by this updater
298      * with the results of applying the given function, returning the updated
299      * value. The function should be side-effect-free, since it may be
300      * re-applied when attempted updates fail due to contention among threads.
301      *
302      * @param obj An object whose field to get and set
303      * @param updateFunction a side-effect-free function
304      * @return the updated value
305      * @since 1.8
306      */
307     public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
308         int prev, next;
309         do {
310             prev = get(obj);
311             next = updateFunction.applyAsInt(prev);
312         } while (!compareAndSet(obj, prev, next));
313         return next;
314     }
315 
316     /**
317      * Atomically updates the field of the given object managed by this
318      * updater with the results of applying the given function to the
319      * current and given values, returning the previous value. The
320      * function should be side-effect-free, since it may be re-applied
321      * when attempted updates fail due to contention among threads.  The
322      * function is applied with the current value as its first argument,
323      * and the given update as the second argument.
324      *
325      * @param obj An object whose field to get and set
326      * @param x the update value
327      * @param accumulatorFunction a side-effect-free function of two arguments
328      * @return the previous value
329      * @since 1.8
330      */
331     public final int getAndAccumulate(T obj, int x,
332                                       IntBinaryOperator accumulatorFunction) {
333         int prev, next;
334         do {
335             prev = get(obj);
336             next = accumulatorFunction.applyAsInt(prev, x);
337         } while (!compareAndSet(obj, prev, next));
338         return prev;
339     }
340 
341     /**
342      * Atomically updates the field of the given object managed by this
343      * updater with the results of applying the given function to the
344      * current and given values, returning the updated value. The
345      * function should be side-effect-free, since it may be re-applied
346      * when attempted updates fail due to contention among threads.  The
347      * function is applied with the current value as its first argument,
348      * and the given update as the second argument.
349      *
350      * @param obj An object whose field to get and set
351      * @param x the update value
352      * @param accumulatorFunction a side-effect-free function of two arguments
353      * @return the updated value
354      * @since 1.8
355      */
356     public final int accumulateAndGet(T obj, int x,
357                                       IntBinaryOperator accumulatorFunction) {
358         int prev, next;
359         do {
360             prev = get(obj);
361             next = accumulatorFunction.applyAsInt(prev, x);
362         } while (!compareAndSet(obj, prev, next));
363         return next;
364     }
365 
366     /**
367      * Standard hotspot implementation using intrinsics.
368      */
369     private static final class AtomicIntegerFieldUpdaterImpl<T>
370         extends AtomicIntegerFieldUpdater<T> {
371         private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
372         private final long offset;
373         /**
374          * if field is protected, the subclass constructing updater, else
375          * the same as tclass
376          */
377         private final Class<?> cclass;
378         /** class holding the field */
379         private final Class<T> tclass;
380 
381         AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
382                                       final String fieldName,
383                                       final Class<?> caller) {
384             final Field field;
385             final int modifiers;
386             try {
387                 field = AccessController.doPrivileged(
388                     new PrivilegedExceptionAction<Field>() {
389                         public Field run() throws NoSuchFieldException {
390                             return tclass.getDeclaredField(fieldName);
391                         }
392                     });
393                 modifiers = field.getModifiers();
394                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
395                     caller, tclass, null, modifiers);
396                 ClassLoader cl = tclass.getClassLoader();
397                 ClassLoader ccl = caller.getClassLoader();
398                 if ((ccl != null) && (ccl != cl) &&
399                     ((cl == null) || !isAncestor(cl, ccl))) {
400                     sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
401                 }
402             } catch (PrivilegedActionException pae) {
403                 throw new RuntimeException(pae.getException());
404             } catch (Exception ex) {
405                 throw new RuntimeException(ex);
406             }
407 
408             if (field.getType() != int.class)
409                 throw new IllegalArgumentException("Must be integer type");
410 
411             if (!Modifier.isVolatile(modifiers))
412                 throw new IllegalArgumentException("Must be volatile type");
413 
414             // Access to protected field members is restricted to receivers only
415             // of the accessing class, or one of its subclasses, and the
416             // accessing class must in turn be a subclass (or package sibling)
417             // of the protected member's defining class.
418             // If the updater refers to a protected field of a declaring class
419             // outside the current package, the receiver argument will be
420             // narrowed to the type of the accessing class.
421             this.cclass = (Modifier.isProtected(modifiers) &&
422                            tclass.isAssignableFrom(caller) &&
423                            !isSamePackage(tclass, caller))
424                           ? caller : tclass;
425             this.tclass = tclass;
426             this.offset = U.objectFieldOffset(field);
427         }
428 
429         /**
430          * Returns true if the second classloader can be found in the first
431          * classloader's delegation chain.
432          * Equivalent to the inaccessible: first.isAncestor(second).
433          */
434         private static boolean isAncestor(ClassLoader first, ClassLoader second) {
435             ClassLoader acl = first;
436             do {
437                 acl = acl.getParent();
438                 if (second == acl) {
439                     return true;
440                 }
441             } while (acl != null);
442             return false;
443         }
444 
445         /**
446          * Returns true if the two classes have the same class loader and
447          * package qualifier
448          */
449         private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
450             return class1.getClassLoader() == class2.getClassLoader()
451                    && Objects.equals(getPackageName(class1), getPackageName(class2));
452         }
453 
454         private static String getPackageName(Class<?> cls) {
455             String cn = cls.getName();
456             int dot = cn.lastIndexOf('.');
457             return (dot != -1) ? cn.substring(0, dot) : "";
458         }
459 
460         /**
461          * Checks that target argument is instance of cclass.  On
462          * failure, throws cause.
463          */
464         private final void accessCheck(T obj) {
465             if (!cclass.isInstance(obj))
466                 throwAccessCheckException(obj);
467         }
468 
469         /**
470          * Throws access exception if accessCheck failed due to
471          * protected access, else ClassCastException.
472          */
473         private final void throwAccessCheckException(T obj) {
474             if (cclass == tclass)
475                 throw new ClassCastException();
476             else
477                 throw new RuntimeException(
478                     new IllegalAccessException(
479                         "Class " +
480                         cclass.getName() +
481                         " can not access a protected member of class " +
482                         tclass.getName() +
483                         " using an instance of " +
484                         obj.getClass().getName()));
485         }
486 
487         public final boolean compareAndSet(T obj, int expect, int update) {
488             accessCheck(obj);
489             return U.compareAndSwapInt(obj, offset, expect, update);
490         }
491 
492         public final boolean weakCompareAndSet(T obj, int expect, int update) {
493             accessCheck(obj);
494             return U.compareAndSwapInt(obj, offset, expect, update);
495         }
496 
497         public final void set(T obj, int newValue) {
498             accessCheck(obj);
499             U.putIntVolatile(obj, offset, newValue);
500         }
501 
502         public final void lazySet(T obj, int newValue) {
503             accessCheck(obj);
504             U.putOrderedInt(obj, offset, newValue);
505         }
506 
507         public final int get(T obj) {
508             accessCheck(obj);
509             return U.getIntVolatile(obj, offset);
510         }
511 
512         public final int getAndSet(T obj, int newValue) {
513             accessCheck(obj);
514             return U.getAndSetInt(obj, offset, newValue);
515         }
516 
517         public final int getAndAdd(T obj, int delta) {
518             accessCheck(obj);
519             return U.getAndAddInt(obj, offset, delta);
520         }
521 
522         public final int getAndIncrement(T obj) {
523             return getAndAdd(obj, 1);
524         }
525 
526         public final int getAndDecrement(T obj) {
527             return getAndAdd(obj, -1);
528         }
529 
530         public final int incrementAndGet(T obj) {
531             return getAndAdd(obj, 1) + 1;
532         }
533 
534         public final int decrementAndGet(T obj) {
535             return getAndAdd(obj, -1) - 1;
536         }
537 
538         public final int addAndGet(T obj, int delta) {
539             return getAndAdd(obj, delta) + delta;
540         }
541 
542     }
543 }
View Code

 

4.2 AtomicIntegerFieldUpdater 类使用示例

 1 public class AtomicIntegerFieldUpdaterTest {
 2     public static void main(String[] args) {
 3         AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
 4 
 5         User user = new User("Java", 22);
 6         System.out.println(a.getAndIncrement(user));// 22
 7         System.out.println(a.get(user));// 23
 8     }
 9 }
10 
11 class User {
12     private String name;
13     public volatile int age;
14 
15     public User(String name, int age) {
16         super();
17         this.name = name;
18         this.age = age;
19     }
20 
21     public String getName() {
22         return name;
23     }
24 
25     public void setName(String name) {
26         this.name = name;
27     }
28 
29     public int getAge() {
30         return age;
31     }
32 
33     public void setAge(int age) {
34         this.age = age;
35     }
36 }

输出结果:

1 22
2 23

 

posted @ 2022-03-28 19:34  r1-12king  阅读(494)  评论(0编辑  收藏  举报