转载自:https://segmentfault.com/a/1190000015831791?utm_source=tag-newest#articleHeader0
就是以原子方式更新对象引用。
可以看到它持有一个对象的引用,-value,用volatile修饰,并通过unsafe类来操作该引用。
1 private static final Unsafe unsafe = Unsafe.getUnsafe(); 2 private static final long valueOffset; 3 4 static { 5 try { 6 valueOffset = unsafe.objectFieldOffset 7 (AtomicReference.class.getDeclaredField("value")); 8 } catch (Exception ex) { throw new Error(ex); } 9 } 10 11 private volatile V value; 12 13 /** 14 * Creates a new AtomicReference with the given initial value. 15 * 16 * @param initialValue the initial value 17 */ 18 public AtomicReference(V initialValue) { 19 value = initialValue; 20 } 21 22 /** 23 * Creates a new AtomicReference with null initial value. 24 */ 25 public AtomicReference() { 26 }
为什么需要AtomicReference?难道多个线程同时对一个引用变量赋值也会出现并发问题?
引用变量的赋值本身没有并发问题,也就是说对于引用变量var ,类似下面的赋值操作本身就是原子操作:Foo var = ... ;
AtomicReference的引入是为了可以用一种类似乐观锁的方式操作共享资源,在某些情景下以提升性能。
我们知道,当多个线程同时访问共享资源时,一般需要以加锁的方式控制并发:
volatile Foo sharedValue = value;
Lock lock = new ReentrantLock();
lock.lock();
try{
// 操作共享资源sharedValue
}
finally{
lock.unlock();
}
上述访问方式其实是一种对共享资源加悲观锁的访问方式。
而AtomicReference提供了以无锁方式访问共享资源的能力,看看如何通过AtomicReference保证线程安全,来看个具体的例子:
1 package com.citi.test.mutiplethread.demo0503; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.atomic.AtomicReference; 6 7 public class AtomicReferenceTest { 8 public static void main(String[] args) throws InterruptedException { 9 AtomicReference<Integer> ref=new AtomicReference<Integer>(new Integer(1000)); 10 List<Thread> list=new ArrayList<Thread>(); 11 for(int i=0;i<1000;i++){ 12 Thread t=new Thread(new Task(ref),"Thread-"+i); 13 list.add(t); 14 t.start(); 15 } 16 for(Thread t: list){ 17 System.out.println(t.getName()); 18 t.join(); 19 } 20 System.out.println(ref.get()); 21 } 22 } 23 class Task implements Runnable{ 24 private AtomicReference<Integer> ref; 25 public Task(AtomicReference<Integer> ref) { 26 this.ref=ref; 27 } 28 @Override 29 public void run() { 30 for(;;){ 31 Integer oldV=ref.get(); 32 System.out.println(Thread.currentThread().getName()+":"+oldV); 33 if(ref.compareAndSet(oldV, oldV+1)){ 34 break; 35 } 36 } 37 } 38 }