Java原子操作类
Java原子操作类
什么是原子操作?
原子操作(Atomic Operation),意为”不可被中断的一个或一系列操作”。
- 处理器使用基于对缓存加锁或总线加锁的方式,来实现多处理器之间的原子操作。
- 在 Java 中,可以通过锁和循环 CAS 的方式来实现原子操作。CAS操作 —— Compare & Set ,或是 Compare & Swap ,现在几乎所有的 CPU 指令都支持 CAS 的原子操作。
原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。
- int++ 并不是一个原子操作,所以当一个线程读取它的值并加 1 时,另外一个线程有可能会读到之前的值,这就会引发错误。
- 为了解决这个问题,必须保证增加操作是原子的,在 JDK5 之前我们可以使用同步技术来做到这一点。到 JDK5 后,java.util.concurrent.atomic 包提供了 int 和 long 类型的原子包装类,它们可以自动的保证对于他们的操作是原子的并且不需要使用同步。
java.util.concurrent 这个包里面提供了一组原子类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由 JVM 从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。
- 原子类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference 。
- 原子数组:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray 。
- 原子属性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater 。
- 解决 ABA 问题的原子类:AtomicMarkableReference(通过引入一个boolean 来反映中间有没有变过),AtomicStampedReference(通过引入一个 int 来累加来反映中间有没有变过)。
关于 CAS 的内容,建议胖友在看看 《【死磕 Java 并发】—- 深入分析 CAS》 。
CAS 操作有什么缺点?
1)ABA 问题
比如说一个线程 one 从内存位置 V 中取出 A ,这时候另一个线程 two 也从内存中取出 A ,并且 two 进行了一些操作变成了 B ,然后 two 又将 V 位置的数据变成 A ,这时候线程 one 进行 CAS 操作发现内存中仍然是 A ,然后 one 操作成功。尽管线程 one 的 CAS 操作成功,但可能存在潜藏的问题。
从 Java5 开始 JDK 的 atomic包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。
2)循环时间长开销大
对于资源竞争严重(线程冲突严重)的情况,CAS 自旋的概率会比较大,从而浪费更多的 CPU 资源,效率低于 synchronized 。
3)只能保证一个共享变量的原子操作
当对一个共享变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操作,但是对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁。
本文由作者按照 CC BY 4.0 进行授权