Java中的原子操作类
2018-03-30 13:35
120 查看
一:为什么需原子操作类
当程序更新一个变量时,如果多个线程同时更新,那么我们可能得不到期望值。通常我们使用synchronized解决这个问题。
从JDK1.5开始,在java.util.concurrent.atomic 包的原子操作类提供了一种用法简单、高效、线程安全地更新一个变量的方式。
类 AtomicBoolean、AtomicInteger、AtomicLong 和 AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。
二:原子更新基本数据类型
下面以AtomicInteger为例:
对于这些方法:i. addAndGet(1); -> ++i
i. getAndAdd(1); -> i++
那么它们是如何实现原子操作的? public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
因为compareAndSwapInt的源码无法追到,我们采用分析的方式来解释CAS算法的逻辑。
多线程并发的情况下,如果this值与expect值相等,则将update值赋值给this,更新成功返回true。若this值与expect值不相等,则说另一个线程已经访问并修改了值,则返回false,说明更新失败。
代码没有加锁,那么另一个线程是如何得知值已经被修改了? private volatile int value; volatile修饰的变量,多线程间可见。一个线程修改了value值,其它正在访问value的线程也得到通知(value值已经被更改,值可见)。
三:原子跟新数组
以AtomicIntegerArray为例
构造函数
源代码分析:数组通过构造方法传递进去,然后AtomicIntegerArray会将传入的数组复制一份。所以AtomicIntegerArray对内部的元素进行操作时,不会影响传入的数组。
四:更新引用类型的数据
AtomicReference也实现了compareAndSet方法进行原子操作。
五:原子更新字段类
①原子更新字段类都是抽象类,每次使用都必须使用静态方法newUpdater()创建一个更新器,并且设置想要更新的类和属性。
②更新类的字段必须使用public volatile修饰符。
当程序更新一个变量时,如果多个线程同时更新,那么我们可能得不到期望值。通常我们使用synchronized解决这个问题。
从JDK1.5开始,在java.util.concurrent.atomic 包的原子操作类提供了一种用法简单、高效、线程安全地更新一个变量的方式。
类 AtomicBoolean、AtomicInteger、AtomicLong 和 AtomicReference 的实例各自提供对相应类型单个变量的访问和更新。每个类也为该类型提供适当的实用工具方法。
二:原子更新基本数据类型
AtomicBoolean | 可以用原子方式更新的 boolean 值。 |
AtomicInteger | 可以用原子方式更新的 int 值。 |
AtomicLong | 可以用原子方式更新的 long 值。 |
int | addAndGet(int delta) 以原子方式将给定值与当前值相加。 |
boolean | compareAndSet(int expect, int update) 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 |
int | decrementAndGet() 以原子方式将当前值减 1。 |
int | get() 获取当前值。 |
int | getAndAdd(int delta) 以原子方式将给定值与当前值相加。 |
int | getAndDecrement() 以原子方式将当前值减 1。 |
int | getAndIncrement() 以原子方式将当前值加 1。 |
int | getAndSet(int newValue) 以原子方式设置为给定值,并返回旧值。 |
int | incrementAndGet() 以原子方式将当前值加 1。 |
int | intValue() 以 int 形式返回指定的数值。 |
i. getAndAdd(1); -> i++
那么它们是如何实现原子操作的? public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
因为compareAndSwapInt的源码无法追到,我们采用分析的方式来解释CAS算法的逻辑。
多线程并发的情况下,如果this值与expect值相等,则将update值赋值给this,更新成功返回true。若this值与expect值不相等,则说另一个线程已经访问并修改了值,则返回false,说明更新失败。
代码没有加锁,那么另一个线程是如何得知值已经被修改了? private volatile int value; volatile修饰的变量,多线程间可见。一个线程修改了value值,其它正在访问value的线程也得到通知(value值已经被更改,值可见)。
三:原子跟新数组
AtomicIntegerArray | 可以用原子方式更新其元素的 int 数组。 |
AtomicLongArray | 可以用原子方式更新其元素的 long 数组。 |
AtomicReferenceArray<E> | 可以用原子方式更新其元素的对象引用数组。 |
构造函数
AtomicIntegerArray(int length) 创建给定长度的新 AtomicIntegerArray。 |
AtomicIntegerArray(int[] array) 创建与给定数组具有相同长度的新 AtomicIntegerArray,并从给定数组复制其所有元素。 |
public AtomicIntegerArray(int[] array) { // Visibility guaranteed by final field guarantees this.array = array.clone(); }
源代码分析:数组通过构造方法传递进去,然后AtomicIntegerArray会将传入的数组复制一份。所以AtomicIntegerArray对内部的元素进行操作时,不会影响传入的数组。
四:更新引用类型的数据
AtomicMarkableReference<V> | AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。 |
AtomicReference<V> | 可以用原子方式更新的对象引用。 |
AtomicStampedReference<V> | AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。 |
boolean | compareAndSet(V expect, V update) 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。 |
五:原子更新字段类
AtomicIntegerFieldUpdater<T> | 基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。 |
AtomicLongFieldUpdater<T> | 基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新 |
AtomicReferenceFieldUpdater<T,V> | 基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。 |
②更新类的字段必须使用public volatile修饰符。
相关文章推荐
- 多线程编程入门(9):原子性操作类(java.util.concurrent.atomic)
- Java并发库(八):java5原子性操作类的应用
- 第七章 Java中的13个原子操作类(atomic包)
- java并发之原子操作类和非阻塞算法
- java并发编程:线程安全管理类--原子操作类--AtomicBoolean
- Java线程(三):JUC包原子性操作类与线程池的简单运用
- Java中的原子操作类
- java原子操作类-原子数组类
- 多线程之4-------java 5原子性操作类的应用
- Java中的13个原子操作类(六)
- 08_张孝祥_多线程_java5原子性操作类的应用
- Java中13个原子操作类、Unsafe类
- Java原子操作类汇总
- java.util.concurrent.atomic 并发包下的原子操作类(AtomicBoolean,AtomicInteger,AtomicLong......))
- 【Java多线程与并发库】07 Java中的13个原子操作类
- java.util.concurrent.atomic原子操作类包
- 黑马程序员-java5原子性操作类的应用
- java5原子性操作类的应用(八)
- java5原子性操作类的应用
- Java中的原子操作类