这段代码我们除了用synchronized来保证原子性我们还有别的什么办法吗?
我们来看一下这种方法
真是太神奇了,不用加synchronized锁也能保证并发下的原子性。那么AtomicInteger是什么呢?
AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。
那我们来通过进入getAndIncrement()方法里探究一下为什么这个类能够保证原子性呢?
这个方法里的compareAndSet()方法也就是大名鼎鼎的CAS操作啦。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。
如果当前内存位置的值等于预期原值A的话,就将B赋值。否则,处理器 不做任何操作。整个比较并替换的操作是一个原子操作。这样做就不用害怕其它线程同时修改变量。
CAS虽然能够高效的保证原子性,但是它还是存在着ABA问题以及循环开销大等缺点
- ABA问题:如果另外一个线程在这个线程进行CAS比较的途中,将内存位置的值已经进行了操作,但是操作结果又将内存位置的值改为了预期原值,这个时候这个线程在比较的时候会发现内存位置和预期原值是相等的所以进行了替换操作,事实上另外一个线程已经对这个内存位置的值进行了操作,但是当前线程并不能发现这个问题。这就是ABA问题。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一
- 循环开销大:自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
- 只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性。