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中的原子变量的主要内容,如果未能解决你的问题,请参考以下文章

高并发第八弹:J.U.C起航(java.util.concurrent)

24.Java中atomic包中的原子操作类总结

原子片段:原子编辑器中的多行片段

Java多线程之原子操作类

并发之atomic原子操作

如何创建片段以重复变量编号中的代码行