jdk1.5后提供了java.util.concurrent.atomic包,其中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。
Atomic包提供了4种类型的13个原子更新类来完成原子更新,Atomic包里的类基本都是使用Unsafe实现的包装类,具体见下表
| 更新方式 | 具体实现类 | 主要方法说明 | 备注 |
|---|---|---|---|
| 原子更新基本类型类 | AtomicBoolean: 原子更新布尔类型 | 这3个类提供的方法差不多相同,这里以AtomicInteger为例进行介绍。1. int addAndGet(int delta): 以原子方式将输入的数值与实例中的值相加,并返回结果;2. boolean compareAndSet(int expect, int update): 如果输入的数值等于预期值,则以原子方式将该值设置为输入的值;3. int getAndIncrement(): 以原子方式将当前值加1,注意这里返回的是自增前的值;4. void lazySet(int newValue): 最终会设置成newValue,可能导致其他线程在之后的一小段时间内还可以读到旧的值;5. int getAndSet(int newValue): 以原子方式设置为newValue的值,并返回旧值。 | 原子更新char、float、double变量可以采用类似于先将变量类型转为整型,再使用compareAndSwapInt进行CAS。 |
| AtomicInteger: 原子更新整型 | |||
| AtomicLong: 原子更新长整型 | |||
| 原子更新数组 | AtomicIntegerArray: 原子更新整型数组里的元素 | 以AtomicIntegerArray类为例,常用方法有:① int addAndGet(int i, int delta): 以原子方式将输入值与数组中索引i的元素相加;② boolean compareAndSet(int i, int expect, int update): 如果当前值等于预期值,则以原子方式将数组位置i 的元素设置成update值。 | AtomicIntegerArray中数组value[]通过构造方法传递进去,AtomicIntegerArray会将当前数组复制一份,所以内部元素进行修改时,用value[]得到的值不变。 |
| AtomicLongArray: 原子更新长整型数组里的元素 | |||
| AtomicReferenceArray: 原子更新引用类型数组里的元素 | |||
| 原子更新引用类 | AtomicReference: 原子更新引用类 | 方法与原子更新基本类型类似 | AtomicInteger只能更新一个变量,可以使用这个原子更新引用类型提供的类来一次更新多个变量的值 |
| AtomicReferenceFieldUpdater: 原子更新引用类型里的字段 | |||
| AtomicMarkableReference: 原子更新带有标记位的引用类型,可以原子更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef, boolean initialMark) | |||
| 原子更新字段类 | AtomicIntegerFieldUpdater: 原子更新整型字段的更新器 | 成员方法与上面的大同小异 | 两步原子更新字段类:① 因为原子更新字段类都是抽象类,所以使用时要用静态方法newUpdater()创建一个更新器,并设置想要更新的类和属性;② 更新类的字段(属性)必须使用public volatile修饰符。 |
| AtomicLongFieldUpdater: 原子更新长整形字段的更新器 | |||
| AtomicStampedReference: 原子更新带有版本号的引用类型,该类型将整型值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决CAS出现的ABA问题。 |