[TOC]
AtomicReference
作用
原子类(CAS+volatile)的引入是为了可以用一种类似乐观锁的方式操作共享资源,而不用依靠悲观锁模式
说明
1.value是volatile类型。这保证了:当某线程修改value的值时,其他线程看到的value值都是最新的value值,即修改之后的volatile的值。
2.通过CAS设置value。这保证了:当某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作是原子的,即线程在操作value时不会被中断。
CAS的缺点
- 循环时间长,开销大
- 只能保证一个共享变量的操作
- ABA问题
示例
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。
1.紧接着,通过CAS函数对它进行设置。如果ar的值为p1的话,则将其设置为p2。
2.最后,获取ar对应的对象,并打印结果。p3.equals(p1)的结果为false,这是因为Person并没有覆盖equals()方法,而是采用继承自Object.java的equals()方法;而Object.java中的equals()实际上是调用”==”去比较两个对象,即比较两个对象的地址是否相等。
-
为什么要重写equals和hashcode
例如hashmap采用自定义的对象作为key,如果不重写hashcode和equals的时候,取落点和链表equals的比较都是内存地址的比较。
ABA问题解决
AtomicStampedReference就是上面所说的加了版本号的AtomicReference。
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
}