概览
原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。
在java中提供了很多原子类,笔者在此主要把这些原子类分成四大类。
原子更新基本类型
相关实现类:AtomicBoolean、AtomicInteger、AtomicLong。主要就是用来基本类型的操作
原子更新数组类型
相关实现类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。可以原子化地更新数组里面的每一个元素,和原子更新基本类型差别就是基本上方法都多了个数组的下标。
原子更新引用类型
相关实现类:AtomicReference、AtomicStampedReference 、AtomicMarkableReference。这个就要重点关注ABA,但是Java已经关注到了所以AtomicStampedReference 和 AtomicMarkableReference 就能避免ABA问题了,就是用了版本号!
原子更新字段类型
相关实现类:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 它们可以原子化地更新对象的属性,注意更新类的字段(属性)必须使用public volatile修饰符,这样才能保证可见性。
原子累加器
相关实现类:LongAccumulator、LongAdder、DoubleAccumulator、DoubleAdder。这几个类只能用来进行累加操作,现对于原子更新基本类型它们的性能更好些,所以如果只有累加操作可以用这几个类!
CAS 指令包含 3 个参数:共享变量的内存地址 A、用于比较的值 B 和共享变量的新值 C。只有当内存中地址A的值等于B,才能把地址A的值变成C。
也就是只有预期值B等于内存地址A中的值时,表明共享变量没有被其他线程修改过,所以才允许更新新值,这样就保证了原子性!
CAS还会有ABA问题,就是当你比较的时候,可能你的值被一个线程改了之后,另一个线程又改了回来,然后你比较的时候发现和预期值一样,其实是被改过的。
通常利用CAS来解决并发问题都通过自旋手段,这里的自旋的其实循环尝试,再说白一点就是while循环。