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 }
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 }
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 }
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 }
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