youyichannel

志于道,据于德,依于仁,游于艺!

0%

Atomic原子操作类

原子性说明

无论存在多少个子操作,只要将这部分操作通过加锁的形式进行锁定,那么就可以视为一个原子性操作。

原子性操作 <=> 线程安全

原子操作类概述

原子操作类:提供了可以保证线程安全的类,可以直接使用。

当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i + 1,B线程也更新i + 1,经过两个线程操作之后可能i不等于3,而是等于2。

解决方案:

  1. 加锁
  2. 使用volatile修饰变量i
  3. 使用原子操作类

JDK5开始提供了java.util.concurrent.atomic包,这个包中的原子操作类提供了一种用法简单、性能高效(CAS)、线程安全地更新一个变量的方式。因为变量的类型有很多种,所以在Atomic包里一共提供了13个类,属于4种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。Atomic包里的类基本都是使用Unsafe实现的包装类。

使用原子操作类,简单,方法见名知义。

特别的,如果需要原子性地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下3个类进行原子字段更新:

  • AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
  • AtomicLongFieldupdater:原子更新长整型字段的更新器。
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解決使用CAS进行原子更新时可能出现的ABA问题。

要想原子地更新字段类需要两步:

  1. 因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater创建一个更新器,并且需要设置想要更新的类和属性
  2. 更新类的宇段(属性)必须使用public volatile修饰符

对于原子更新数组类和原子更新对象引用类,实质上就是将数组和对象的外层使用Atomic封装,因此在进行替换的时候,其实是外层这个封装保证了原子性。同理,原子更新基本类型,如Integer,也是一个对象,同样也是在外层进行了一次封装。