AtomicInteger 是对 int 类型的一个封装,提供了原子性的访问和更新操作,其原子性操作的实现是基于CAS(compare-and-swap)技术。
AtomicInteger 提供一种线程安全的加减操作接口。
- public final int get() //获取当前的值
- public final int getAndSet(int newValue)//获取当前的值,并设置新的值
- public final int getAndIncrement() //获取当前的值,并自增
- public final int getAndDecrement() //获取当前的值,并自减
- public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
看看 AtomicInteger 源代码:
private volatile int value;
volatile 关键字是保证AtomicInteger 线程安全的根源。
volatile 修饰的成员变量,在每次被线程访问时,都强迫从共享内存重新读取该成员的值,而且,当成员变量值发生变化时,强迫将变化的值重新写入共享内存,这样两个不同的线程在访问同一个共享变量的值时,始终看到的是同一个值。
Java语言规范指出:为了获取最佳的运行速度,允许线程保留共享变量的副本,当这个线程进入或者离开同步代码块时,才与共享成员变量进行比对,如果有变化再更新共享成员变量。这样当多个线程同时访问一个共享变量时,可能会存在值不同步的现象。
而volatile这个值的作用就是告诉VM:对于这个成员变量不能保存它的副本,要直接与共享成员变量交互。
建议:当多个线程同时访问一个共享变量时,可以使用volatile,而当访问的变量已在synchronized代码块中时,不必使用。
缺点:使用volatile将使得VM优化失去作用,导致效率较低,所以要在必要的时候使用。
CAS(compare-and-swap)所谓CAS,表示的是一系列操作的集合,获取当前值,进行运算,利用CAS 指令试图进行更新。
如果当前数值未变,表示没有其他线程进行并发修改,则成功更新。
否则,可能出现不同的选择,要么进行重试,要么就返回一个成功或者失败的结果。
CAS就是Compare and Swap的意思,比较并操作。
CAS有3个操作数:
- V:内存中的值。
- B:要修改为的新值。
- A:若V==A则V=B。
其实CAS的过程也是挺简单的,来一发流程图吧。
CAS简而言之就是:CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
CAS 是Java并发中所谓 lock-free 机制的基础。
CAS 也并不是没有副作用,试想,其常用的失败重试机制,隐含着一个假设,即竞争情况是短暂的。大多数应用场景下,确实大部分重试只会发生一次就获得了成功,但是总是有意外情况,所以在有需要的时候,还是要考虑限制自旋的次数,以免过度消耗CPU。
AbstractQueuedSynchronizer(AQS)是Java 并发包中,实现各种同步结构的基础。
AQS 内部数据和方法,可以简单拆分为:
- 一个volatile 的整数成员状态,同时提供了setState() 和 getState() 方法;
- private volatile int state;
- 一个先进先出(FIFO)的等待线程队列(waiter),实现多线程间竞争和等待,是AQS 机制的核心之一;
- 各种基于 CAS 的基础操作方法,以及各种期望具体同步结构去实现的 acquire/release 方法;
利用AQS 实现一个同步结构,至少需要实现2个基本类型的方法,分别是 acquire 操作,获取资源的独占权;还有就是 release 操作,释放对某个资源的独占。
,