使用原子的方式更新基本类型,Atomic包提供了以下3个类。AtomicBoolean: 原子更新布尔类型。AtomicInteger: 原子更新整型。AtomicLong: 原子更新长整型。以上3个类提供的方法几乎一模一样,可以参考上面AtomicInteger中的相关方法。# 原子更新数组通过原子的方式更新数组里的某个元素,Atomic包提供了以下的3个类:AtomicIntegerArray: 原子更新整型数组里的元素。AtomicLongArray: 原子更新长整型数组里的元素。AtomicReferenceArray: 原子更新引用类型数组里的元素。这三个类的最常用的方法是如下两个方法:get(int index):获取索引为index的元素值。compareAndSet(int i,E expect,E update): 如果当前值等于预期值,则以原子方式将数组位置i的元素设置为update值。举个AtomicIntegerArray例子:import java.util.concurrent.atomic.AtomicIntegerArray;
public class Demo5 {
public static void main(String[] args) throws InterruptedException {
AtomicIntegerArray array = new AtomicIntegerArray(new int[] { 0, 0 });
System.out.println(array);
System.out.println(array.getAndAdd(1, 2));
System.out.println(array);
}
}
输出结果:[0, 0]
0
[0, 2]
# 原子更新引用类型Atomic包提供了以下三个类:AtomicReference: 原子更新引用类型。AtomicStampedReference: 原子更新引用类型, 内部使用Pair来存储元素值及其版本号。AtomicMarkableReferce: 原子更新带有标记位的引用类型。这三个类提供的方法都差不多,首先构造一个引用对象,然后把引用对象set进Atomic类,然后调用compareAndSet等一些方法去进行原子操作,原理都是基于Unsafe实现,但AtomicReferenceFieldUpdater略有不同,更新的字段必须用volatile修饰。举个AtomicReference例子:
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
public static void main(String[] args){
// 创建两个Person对象,它们的id分别是101和102。
Person p1 = new Person(101);
Person p2 = new Person(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 {
volatile long id;
public Person(long id) {
this.id = id;
}
public String toString() {
return "id:"+id;
}
}
结果输出:p3 is id:102
p3.equals(p1)=false
结果说明:新建AtomicReference对象ar时,将它初始化为p1。紧接着,通过CAS函数对它进行设置。如果ar的值为p1的话,则将其设置为p2。最后,获取ar对应的对象,并打印结果。p3.equals(p1)的结果为false,这是因为Person并没有覆盖equals()方法,而是采用继承自Object.java的equals()方法;而Object.java中的equals()实际上是调用"=="去比较两个对象,即比较两个对象的地址是否相等。
原文链接:https://pdai.tech/md/java/thread/java-thread-x-juc-AtomicInteger.html
|