Java多线程系列--(JUC原子类)
欢迎来到飞之折翼的简书,待双翼饱满就是飞翔之际!
源自摘要:https://www.cnblogs.com/skywang12345/p/java_threads_category.html
一、框架
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类。
1.基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;
2.数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;
3.引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference ;
4.对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater 。
这些类存在的目的是对相应的数据进行原子操作。所谓原子操作,是指操作过程不会被中断,保证数据操作是以原子方式进行的。
AtomicLong是作用是对长整形进行原子操作。
在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型
AtomicLong的代码很简单,下面仅以incrementAndGet()为例,对AtomicLong的原理进行说明。
incrementAndGet()源码如下
publicfinallong incrementAndGet() {
for (;;) {
// 获取AtomicLong当前对应的long值
longcurrent = get();
// 将current加1
longnext = current + 1;
// 通过CAS函数,更新current的值
if (compareAndSet(current, next))
return next;
}
}
(01) incrementAndGet()首先会根据get()获取AtomicLong对应的long值。该值是volatile类型的变量,get()的源码如下:
// value是AtomicLong对应的long值
privatevolatilelong value;
// 返回AtomicLong对应的long值
publicfinallong get() {
return value;
}
(02) incrementAndGet()接着将current加1,然后通过CAS函数,将新的值赋值给value。
compareAndSet()的源码如下:
publicfinalbooleancompareAndSet(longexpect,long update) {
returnunsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
compareAndSet()的作用是更新AtomicLong对应的long值。它会比较AtomicLong的原始值是否与expect相等,若相等的话,则设置AtomicLong的值为update。
AtomicLongArray的代码很简单,下面仅以incrementAndGet()为例,对AtomicLong的原理进行说明。
incrementAndGet()源码如下:
publicfinallongincrementAndGet(int i) {
returnaddAndGet(i, 1);
}
说明:incrementAndGet()的作用是以原子方式将long数组的索引 i 的元素加1,并返回加1之后的值。
addAndGet()源码如下:
publiclongaddAndGet(inti,long delta) {
// 检查数组是否越界
longoffset = checkedByteOffset(i);
while(true) {
// 获取long型数组的索引 offset 的原始值
longcurrent = getRaw(offset);
// 修改long型值
longnext = current + delta;
// 通过CAS更新long型数组的索引 offset的值。
if (compareAndSetRaw(offset, current, next))
return next;
}
}
说明:addAndGet()首先检查数组是否越界。如果没有越界的话,则先获取数组索引i的值;然后通过CAS函数更新i的值
private boolean compareAndSetRaw(longoffset,longexpect,long update) {
return unsafe.compareAndSwapLong(array, offset, expect, update);
}
AtomicReference的源码比较简单。它是通过"volatile"和"Unsafe提供的CAS函数实现"原子操作。
(01) value是volatile类型。这保证了:当某线程修改value的值时,其他线程看到的value值都是最新的value值,即修改之后的volatile的值。
(02) 通过CAS设置value。这保证了:当某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作是原子的,即线程在操作value时不会被中断。
AtomicReference示例
// AtomicReferenceTest.java的源码import java.util.concurrent.atomic.AtomicReference;publicclass AtomicReferenceTest {
publicstaticvoid main(String[] args){
// 创建两个Person对象,它们的id分别是101和102。
Person p1 =newPerson(101);
Person p2 =newPerson(102);
// 新建AtomicReference对象,初始化它的值为p1对象
AtomicReference ar =new AtomicReference(p1);
// 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
ar.compareAndSet(p1, p2);
Person p3 = (Person)ar.get();
System.out.println("p3 is "+p3);
System.out.println("p3.equals(p1)="+p3.equals(p1));
}
}class Person {
volatilelong id;
publicPerson(long id) {
this.id = id;
}
public String toString() {
return"id:"+id;
}
}
// LongTest.java的源码
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class LongFieldTest {
public static void main(String[] args) {
// 获取Person的class对象
Class cls = Person.class;
// 新建AtomicLongFieldUpdater对象,传递参数是“class对象”和“long类型在类中对应的名称”
AtomicLongFieldUpdater mAtoLong = AtomicLongFieldUpdater.newUpdater(cls, "id");
Person person = new Person(12345678L);
// 比较person的"id"属性,如果id的值为12345678L,则设置为1000。
mAtoLong.compareAndSet(person, 12345678L, 1000);
System.out.println("id="+person.getId());
}
}
class Person {
volatile long id;
public Person(long id) {
this.id = id;
}
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
}
newUpdater()的作用是获取一个AtomicIntegerFieldUpdater类型的对象。
它实际上返回的是CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持long类型的CAS函数。CASUpdater和LockedUpdater都是AtomicIntegerFieldUpdater的子类,它们的实现类似。
它实际上是通过CAS函数操作。如果类的long对象的值是expect,则设置它的值为update。