J.U.C中的原子变量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了J.U.C中的原子变量相关的知识,希望对你有一定的参考价值。
在开发过程中,很多时候都需要用到原子的递增递减操作;而我们知道,常用的i ++ 和 i -- 等操作都不是原子的,它包含了三步操作(读-改-写):首先,读取变量i的值,其次将i执行 +1 或者 -1 操作,最后,将计算后的结果赋值给i;通常情况下,只有加锁才能保证 i ++ 和 i -- 等操作的原子性。值得关注的是,在JDK1.5及之后的所有版本,java.concurrent.util.atomic包下给我们提供了原子变量,原子变量支持原子的递增和递减操作。这里,针对原子变量的底层实现原理及jdk的部分源码,做一些简单的记录。
1:AtomicBoolean,值得注意的是,AtomicBoolean使用了int类型的属性value来表示true和false,在设置、获取及修改的时候,都是针对value的操作。
其中,AtomicLong、AtomicInteger源码与AtomicBoolean相差不大,所以这里不再赘述。
/** * @Comment AtomicBoolean部分源码 */ public class AtomicBoolean implements Serializable { /** * sun.misc.Unsafe类 */ private static final Unsafe unsafe = Unsafe.getUnsafe() ; /** * 属性value的偏移量 */ private static final long valueOffset ; /** * 使用int类型value来表示true和false * 1 - true 0 - false
* volatile 修饰,可以保证value的可见性;
* 即:如果一个线程对value进行了修改,会立马同步到主内存;同时其它线程的本地内存失效,直接读取主内存获取value的值。 */ private volatile int value ; static { try { //获取AtomicBoolean中value属性的内存地址偏移量 valueOffset = unsafe.objectFieldOffset(AtomicBoolean.class.getDeclaredField("value")) ; } catch (Exception e) { throw new Error(e) ; } } /** * 初始化 true-1 false-0 * @param initiavlValue */ public AtomicBoolean(boolean initiavlValue){ this.value = initiavlValue ? 1 : 0 ; } public AtomicBoolean(){} /** * 获取当前值 * @return */ public final boolean get(){ return value != 0 ; } /** * 原子的更新 * @param expect 期望值 * @param update 修改值 * @return */ public final boolean compareAndSet(boolean expect , boolean update){ int e = expect ? 1 : 0 ; int u = update ? 1 : 0 ; //原子的修改value的值,如果value == e ; 修改为u ;否则不修改 ; 返回是否修改成功 return unsafe.compareAndSwapInt(this , valueOffset , e , u) ; } /** * 原子的更新 * @param expect 期望值 * @param update 修改值 * @return */ public final boolean weakCompareAndSet(boolean expect , boolean update){ int e = expect ? 1 : 0 ; int u = update ? 1 : 0 ; //原子的修改value的值,如果value == e ; 修改为u ;否则不修改 ; 返回是否修改成功 return unsafe.compareAndSwapInt(this , valueOffset , e , u) ; } /** * 设置value的值 * @param newValue */ public final void set(boolean newValue){ value = newValue ? 1 : 0 ; } /** * 最终设置值 * @param newValue */ public final void lazySet(boolean newValue){ int v = newValue ? 1 : 0 ; unsafe.putOrderedInt(this , valueOffset , v) ; } /** * 获取老值,设置新值 * @param newValue * @return */ public final boolean getAndSet(boolean newValue){ boolean prev ; do { prev = get() ; }while (!compareAndSet(prev , newValue)) ; return prev ; } public String toString(){ return Boolean.toString(get()) ; } }
2:AtomicIntegerArray
1 /** 2 * @Comment AtomicIntegerArray部分源码 3 */ 4 public class AtomicIntegerArray implements Serializable { 5 6 private static final Unsafe unsafe = Unsafes.get() ; 7 /** 8 * 对象分配时,获取int类型数组的第一个元素的内存地址 9 * 即:相对于数组对象起始地址的偏移地址 10 */ 11 private static final int base = unsafe.arrayBaseOffset(int[].class) ; 12 /** 13 * shift就是用来定位数组中的内存位置,用来移位用的;每向左移动移位,在不越界的情况下,想当于乘以2。 14 * 由于int类型的长度为4,所以,数组第0个角标开始位是0,第1(i)个角标开始位是4,,第二个(i)位置是8, 15 * 也就是偏移位置等于 i * 4,也就是 i << 2;总结出一个乘法转换成移位操作的案例: 16 * a * (一个2的幂(n)的数) = a << n; 给出一个指定2的幂的数,怎么算成n,,参照shift的计算方法 17 */ 18 private static final int shift ; 19 /** 20 * int[]数组,在构造函数中初始化 21 */ 22 private final int[] array ; 23 24 /** 25 * 1: unsafe.arrayIndexScale(int[].class) ; 26 * 标识int数组类型中元素占用字节的个数. 27 * 2: if( ( scale & (scale - 1) ) != 0 ) ; 28 * 验证元素占用的字节是否为2的n次幂 29 * 3: Integer.numberOfLeadingZeros(scale) ; 30 * 标识int类型的scale转换为2进制存储时,前边补0的个数 31 * 31 - Integer.numberOfLeadingZeros(scale) (这里跟内存操作相关,暂时没搞懂为什么用31减...) 32 */ 33 static { 34 int scale = unsafe.arrayIndexScale(int[].class) ; 35 if( ( scale & (scale - 1) ) != 0 ){ 36 throw new Error("data type scale not a power of two") ; 37 } 38 shift = 31 - Integer.numberOfLeadingZeros(scale) ; 39 } 40 /** 41 * 判断角标是否越界 42 * @param i 43 * @return 44 */ 45 private long checkedByteOffset(int i){ 46 if(i < 0 || i >= array.length) 47 throw new IndexOutOfBoundsException("index" + i) ; 48 return byteOffset(i) ; 49 } 50 /** 51 * 返回数组中第i个角标存储的元素的地址偏移量 52 * @param i 53 * @return 54 */ 55 private static long byteOffset(int i){ 56 return (long) (i << shift) + base ; 57 } 58 /** 59 * 根据长度,构造int[] 60 * @param length 61 */ 62 public AtomicIntegerArray(int length){ 63 this.array = new int[length] ; 64 } 65 /** 66 * 根据传入的数组,构造int[] 67 * @param array 68 */ 69 public AtomicIntegerArray(int [] array){ 70 this.array = array.clone() ; 71 } 72 /** 73 * 获取int[]的长度 74 * @return 75 */ 76 public final int length(){ 77 return array.length ; 78 } 79 /** 80 * 获取数组的第i个元素 81 * @param i 82 * @return 83 */ 84 public final int get(int i){ 85 return getRaw(i) ; 86 } 87 /** 88 * 获取array第offset角标的值 89 * @param offset 90 * @return 91 */ 92 private int getRaw(long offset){ 93 return unsafe.getIntVolatile(array , offset) ; 94 } 95 /** 96 * 将第i个角标的值设置为新值 97 * @param i 98 * @param newValue 99 */ 100 public final void set(int i , int newValue){ 101 unsafe.putIntVolatile(array , checkedByteOffset(i) , newValue) ; 102 } 103 /** 104 * 延迟设置值 105 * @param i 106 * @param newValue 107 */ 108 public final void lazySet(int i , int newValue){ 109 unsafe.putOrderedInt(this , checkedByteOffset(i) , newValue) ; 110 } 111 /** 112 * 获取并设置值 113 * @return 114 */ 115 public final int getAndSet(int i , int newValue){ 116 return unsafe.getAndSetInt(this , checkedByteOffset(i) , newValue) ; 117 } 118 /** 119 * 先比较,后设置 120 * @param i 121 * @param expect 122 * @param update 123 * @return 124 */ 125 public final boolean compareAndSet(int i , int expect , int update){ 126 return compareAndSetRaw(checkedByteOffset(i) , expect , update) ; 127 } 128 private boolean compareAndSetRaw(long offset , int expect , int update){ 129 return unsafe.compareAndSwapInt(array , offset , expect , update) ; 130 } 131 public final boolean weakCompareAndSet(int i , int expect , int update){ 132 return compareAndSet(i , expect , update) ; 133 } 134 /** 135 * 线程安全的递增 136 * @param i 137 * @return 138 */ 139 public final int getAndIncrement(int i){ 140 return getAndAdd(i, 1) ; 141 } 142 /** 143 * 线程安全的递减 144 * @param i 145 * @return 146 */ 147 public final int getAndDecrement(int i){ 148 return getAndAdd(i , -1) ; 149 } 150 /** 151 * 为角标为i的元素 加 delta 152 * @param i 153 * @param delta 154 * @return 155 */ 156 public final int getAndAdd(int i , int delta){ 157 return unsafe.getAndAddInt(array , checkedByteOffset(i) , delta) ; 158 } 159 /** 160 * 线程安全的递增,并获取递增后的值 161 * @return 162 */ 163 public final int incrementAndGet(int i){ 164 return getAndAdd(i , 1) + 1 ; 165 } 166 /** 167 * 线程安全的获取递减后的值 168 * @param i 169 * @return 170 */ 171 public final int decrementAndGet(int i){ 172 return getAndAdd(i , -1) - 1 ; 173 } 174 public final int addAndGet(int i , int delta){ 175 return getAndAdd(i , delta) + delta ; 176 } 177 178 @Override 179 public String toString() { 180 int iMax = array.length - 1 ; 181 if(iMax == -1){ 182 return "[]" ; 183 } 184 StringBuilder b = new StringBuilder() ; 185 b.append(‘[‘) ; 186 //两个;;之间没有判断,计算机可以少一步计算,提高性能 187 for(int i = 0 ; ; i ++){ 188 b.append(getRaw(byteOffset(i))) ; 189 if(i == iMax){ 190 return b.append(‘]‘).toString() ; 191 } 192 b.append(‘,‘).append(‘ ‘) ; 193 } 194 } 195 }
3:AtomicReference
1 /** 2 * @Comment AtomicReference部分源码 5 */ 6 public class AtomicReference<V> implements Serializable { 7 8 private static final Unsafe unsafe = Unsafe.getUnsafe() ; 9 /** 10 * 对象地址 11 */ 12 private static final long valueOffset ; 13 /** 14 * 待操作对象 15 */ 16 private volatile V value ; 17 static { 18 try { 19 valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value")) ; 20 }catch (Exception e){ 21 throw new Error(e) ; 22 } 23 } 24 25 /** 26 * 构造器 27 * @param initValue 28 */ 29 public AtomicReference(V initValue){ 30 this.value = initValue ; 31 } 32 public AtomicReference(){} 33 34 /** 35 * 获取当前value 36 * @return 37 */ 38 public final V get(){ 39 return this.value ; 40 } 41 /** 42 * 设置当前value 43 * @param newValue 44 */ 45 public final void set(V newValue){ 46 this.value = newValue ; 47 } 48 /** 49 * 延迟设置 50 * @param newValue 51 */ 52 public final void lazySet(V newValue){ 53 unsafe.putOrderedObject(this , valueOffset , newValue); 54 } 55 /** 56 * 如果对象为期望对象,原子的替换为给定的对象 57 * @param expect 58 * @param update 59 * @return 60 */ 61 public final boolean compareAndSet(V expect , V update){ 62 return unsafe.compareAndSwapObject(this , valueOffset , expect , update) ; 63 } 64 /** 65 * 如果对象为期望对象,原子的替换为给定的对象 66 * @param expect 67 * @param update 68 * @return 69 */ 70 public final boolean weakCompareAndSet(V expect , V update){ 71 return unsafe.compareAndSwapObject(this , valueOffset , expect , update) ; 72 } 73 /** 74 * 原子的设置 75 * @param newValue 76 * @return 77 */ 78 public final V getAndSet(V newValue){ 79 return (V) unsafe.getAndSetObject(this , valueOffset , newValue) ; 80 } 81 @Override 82 public String toString() { 83 return String.valueOf(get()) ; 84 } 85 }
以上是关于J.U.C中的原子变量的主要内容,如果未能解决你的问题,请参考以下文章