Atomic原子类
原子类实现原理:CAS(compare and swap)
- CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
- CAS包含3个参数CAS(V,E,N).V表示要更新的变量, E表示预期值, N表示新值.仅当V值等于E值时, 才会将V的值设为N, 如果V值和E值不同, 则说明已经有其他线程做了更新, 则当前线程什么都不做. 最后, CAS返回当前V的真实值. CAS操作是抱着乐观的态度进行的, 它总是认为自己可以成功完成操作.当多个线程同时使用CAS操作一个变量时, 只有一个会胜出, 并成功更新, 其余均会失败.失败的线程不会被挂起,仅是被告知失败, 并且允许再次尝试, 当然也允许失败的线程放弃操作.基于这样的原理, CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰, 并进行恰当的处理.
原子类的ABA问题
- 所谓ABA就是一个线程在CAS更新变量的时候,该变量已经被别的线程先从A该成了B,再从B该回了A,此时线程还是会CAS成功,因为它认为期望值并没有变
- 解决办法是增加版本号,每次修改版本号加1
- 实现版本号功能的类为AtomicStampedReference
Atomic基本数据类型
- AtomicInteger
- AtomicLong
- AtomicBoolean
Atomic基本类型原子类常用方法
- int get() // 获取当前值
- int getAndSet(int value) // 获取当前值并设置成指定值等价于普通变量的i = value
- int getAndIncrement() // 自增 ,等价于普通变量的i++
- int getAndDecrement() // 自减,等价于普通变量的i--
- int getAndAdd(int Value) // 加上预期值,等价于普通变量的i = i + value
- boolean compareAndSet(int expect, int update) //如果该对象等于期望值,把它更新成update的值,等价于普通变量的`if (i == expect)
AtomicLong 和LongAdder(jdk8新增)
LongAdder的原理:
比如我需要将100 加个10 再加20,那么有下面这两种操作步骤:
第一种:先将100+10 = 110,然后再110+20 得到最终结果 130。
第二种:将100拆成2个50,在第一个50上面加10得到60,在最后一个50上加20得到70,最后将第一操作结果 60 和 第二次的操作结果70相加,得到最终的130。
LongAdder就是第二种操作思路,将原AtomicLong里的value拆成多个value,这样在并发情况下,就将多个线程竞争修改【一个】value属性的机会 --> 多个线程竞争修改【多个】value属性的机会,这样就相当于将性能翻倍。
在竞争激烈的情况下LongAdder的性能比AtomicLong的高很多
数组类型AtomicLongArray
用法和基本基本数据类型相似,但是函数参数会多一个索引i值,如自增getAndIncrement(int i),对数组的对应索引值做更新