AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,底层采用的是compareAndSwapInt实现CAS,比较的是数值是否相等,而AtomicReference则对应普通的对象引用,底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等。也就是它可以保证你在修改对象引用时的线程安全性。

顺便说一下:引用类型的赋值是原子的。虽然虚拟机规范中说64位操作可以不是原子性的,可以分为两个32位的原子操作,但是目前商用的虚拟机几乎都实现了64位原子操作。

.AtomicReference.set(V newValue) 注意此方法是原子的。这个方法里面就一句代码,引用赋值本身它就是原子性的不会被cpu打断的。

源码如下:

public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;

// 获取Unsafe对象,Unsafe的作用是提供CAS操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}

// volatile类型
private volatile V value;

public AtomicReference(V initialValue) {
value = initialValue;
}

public AtomicReference() {
}

public final V get() {
return value;
}

public final void set(V newValue) {
value = newValue;
}

public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
}

public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

public final boolean weakCompareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

public final V getAndSet(V newValue) {
while (true) {
V x = get();
if (compareAndSet(x, newValue))
return x;
}
}

public String toString() {
return String.valueOf(get());
}
}

public class Main{
public static void main(String[] args) {

// 创建两个Person对象,它们的id分别是101和102。
Person2 p1 = new Person2(101);
Person2 p2 = new Person2(102);
// 新建AtomicReference对象,初始化它的值为p1对象
AtomicReference ar = new AtomicReference(p1);
//更改p1的id.
p1.setId(106);
// 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
ar.compareAndSet(p1, p2);

Person2 p3 = (Person2)ar.get();
System.out.println("p3 is "+p3);
System.out.println("p3.equals(p1)="+p3.equals(p1));
}

}
class Person2 {
volatile long id;
public Person2(long id) {
this.id = id;
}
public String toString() {
return "id:"+id;
}
public void setId(long id){
this.id=id;
}
}
运行结果如下:

p3 is id:102
p3.equals(p1)=false

可以看出,修改了p1的id对compareAndSet()并没有影响,因为修改id仅仅改变了p1的成员变量,而AtomicReference底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等。也就是它可以保证你在修改对象引用时的线程安全性。上面代码成功的将原子类中的引用从p1变成p2,而且是线程安全的。

AtomicReference 原子引用的更多相关文章

  1. CAS导致的ABA问题及解决:时间戳原子引用AtomicReference、AtomicStampedReference

    1.CAS导致ABA问题: CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差中会导致数据的变化. 比如:线程1从内存位置V中取出A,这时线程2也从V中取出A ...

  2. Java并发之原子变量和原子引用与volatile

    我们知道在并发编程中,多个线程共享某个变量或者对象时,必须要进行同步.同步的包含两层作用:1)互斥访问(原子性):2)可见性:也就是多个线程对共享的变量互斥地访问,同时线程对共享变量的修改必须对其他线 ...

  3. 《Java并发编程实战》笔记-OneValueCache与原子引用技术

    /** * NumberRange * <p/> * Number range class that does not sufficiently protect its invariant ...

  4. 一篇文章快速搞懂 Atomic(原子整数/CAS/ABA/原子引用/原子数组/LongAdder)

    前言 相信大部分开发人员,或多或少都看过或写过并发编程的代码.并发关键字除了Synchronized,还有另一大分支Atomic.如果大家没听过没用过先看基础篇,如果听过用过,请滑至底部看进阶篇,深入 ...

  5. 详解volatile关键字和原子引用

    本篇看一下Volatile关键字和原子引用. 上图就是JUC包结构,总共分成三块 (1)java.util.concurrent:并发包基础类,包括阻塞队列,线程池相关类,线程安全Map等. (2)j ...

  6. 第47天打卡学习(单例模式 深入了解CAS 原子引用 各种锁的理解)

    18彻底玩转 单例模式 饿汉式 DCL懒汉模式 探究! 饿汉式  package com.kuang.single; //饿汉式单例 //单例模式重要思想是构造器私有 public class Hun ...

  7. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  8. 同步方法、同步代码块、volidate变量的使用

    当多个线程涉及到共享数据的时候,就会设计到线程安全的问题.非线程安全其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”.发生脏读,就是取到的数据已经被其他的线程改过了. ...

  9. 多线程之美6一CAS与自旋锁

    1.什么是CAS CAS 即 compare and swap 比较并交换, 涉及到三个参数,内存值V, 预期值A, 要更新为的值B, 拿着预期值A与内存值V比较,相等则符合预期,将内存值V更新为B, ...

随机推荐

  1. javascript获取文件后缀名

    javascript获取文件后缀名:在需要验证文件格式的时候,首先就要获得文件的格式,下面是一个通过正则表达式获取文件后缀名的一个简单实例. function validate(){ var impo ...

  2. 一道google的面试题(据说)

    1. 原题(同事给的) Max Howell 参加了谷歌的面试,出题人竟然要求 Max Howell 在白板上作出解答,Max Howell 当然愤怒地拒绝了,回家以后马上在微博上跟我们分享他的吐槽: ...

  3. [ZOJ3316]:Game

    题面 vjudge Sol 有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过L,无法拿棋的人输,问后手能否胜利 首先距离 ...

  4. Web前端面试指导(二十):JavaScript中如何翻转一个字符串?

    题目点评 字符串作在程序中是非常常见的,因为程序中绝大部分的数据都可以当作字符串来处理.需要对字符的处理方法比较熟悉,在回答的时候尽量能够说出多种解决方法更好! 字符串翻转的方法 1)使用字符串函数 ...

  5. sql-syscolumns,INFORMATION_SCHEMA.columns,sysobjects

    //计算表tb_Blog的字段个数 select count(*) from syscolumns where id=object_id('tb_Blog') 获取指定表的所有字段和字段类型 SELE ...

  6. Android JazzyViewPager

    JazzyViewPager: package com.itau.jingdong.widgets.jazzviewpager; import java.util.HashMap; import ja ...

  7. ArcGIS 10.1 如何连接数据库(转)

    原文地址:http://blog.csdn.net/arcgis_cs/article/details/7750893 ArcGIS 10.1如何连接数据库 最近在使用ArcGIS 10.1的数据库, ...

  8. Oracle基础之Merge into

    Merge into语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句. 通过MERGE语句,根据一张表或多表联合查询的连接条件对另外一张表进行查询,连接条件匹配上的进行UPDA ...

  9. Qt::FocusPolicy的使用

    http://blog.csdn.net/imxiangzi/article/details/50742813

  10. Memory Leak Detection in C++

    原文链接:http://www.linuxjournal.com/article/6556?page=0,0 An earlier article [“Memory Leak Detection in ...