AtomicReference源码解析及应用与应用拓展

AtomicReference赋值操作是非线程安全的,一般会在数据库中用锁来实现变更赋值,如果不用锁,可以用AtomicReference<V>类,实现将对象进行原子操作。提供了一种读和写都是原子性的对象引用变量。原子意味着多个线程试图改变同一个AtomicReference(例如比较和交换操作)将不会使得AtomicReference处于不一致的状态。

一、源码解析

public class AtomicReference<V> implements Serializable {

    
    private static final long serialVersionUID = -1848883965231344442L;
    private static final Unsafe unsafe = Unsafe.getUnsafe();//通过unsafe实现原子操作
    private static final long valueOffset;
    private volatile V value;//通过volatile实现原子操作

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

    public AtomicReference() {
    }

    //通过原子操作获取当前值
    public final V get() {
        return this.value;
    }

    //不是原子操作-慎用
    public final void set(V var1) {
        this.value = var1;
    }

    //通过 unsafe 实现原子操作
    public final void lazySet(V var1) {
        unsafe.putOrderedObject(this, valueOffset, var1);
    }

    //通过 unsafe 实现原子操作
    /**
     * var1当前值:拿当前值value和var1值去比较,如果相等返回true并更新值为var2期望值
     * var2期望值:如果返回true则更新为期望值,如果返回false则不更新值
     */
    public final boolean compareAndSet(V var1, V var2) {
        return unsafe.compareAndSwapObject(this, valueOffset, var1, var2);
    }

    //通过 unsafe 实现原子操作
    public final boolean weakCompareAndSet(V var1, V var2) {
        return unsafe.compareAndSwapObject(this, valueOffset, var1, var2);
    }

    //原子赋值新值并且返回旧值
    public final V getAndSet(V var1) {
        return unsafe.getAndSetObject(this, valueOffset, var1);
    }

}
二、应用
public class TestClass {

    public static void main(String[] args){
        Customer Customer1 =new Customer("Lucy", BigDecimal.valueOf(99l));
        Customer Customer2 =new Customer("Lily",BigDecimal.valueOf(99l));


        final AtomicReference<Customer> reference = new AtomicReference<>(Customer1);
        Customer customer3 = reference.get();
        if (customer3.equals(Customer1)) {
            System.out.println("Customer3:" + customer3+"name:"+customer3.getName()+"*****"+"value"+customer3.getAmount());
        } else {
            System.out.println("else:" + customer3+"name:"+customer3.getName()+"*****"+"value"+customer3.getAmount());
        }

        boolean b = reference.compareAndSet(null, Customer2);
        System.out.println("myClass.main-"+b+"--"+reference.get()+"name:"+reference.get().getName()+"*****"+"value"+reference.get().getAmount());

        boolean b1 = reference.compareAndSet(Customer1, Customer2);
        System.out.println("myClass.main-"+b1+"--"+reference.get()+"name:"+reference.get().getName()+"*****"+"value"+reference.get().getAmount());


        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread1-----------");

                Customer Customer = reference.get();
                Customer.setName("Lucy1");
                Customer.setAmount(Customer.getAmount().add(BigDecimal.valueOf(100l)));
                reference.getAndSet(Customer);
                System.out.println("Thread1:"+reference.get().toString()+"name:"+reference.get().getName()+"*****"+"value"+reference.get().getAmount());
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread2-----------");

                Customer Customer = reference.get();
                Customer.setName("Lucy2");
                Customer.setAmount(Customer.getAmount().add(BigDecimal.valueOf(100l)));
                reference.getAndSet(Customer);
                System.out.println("Thread2:"+reference.get().toString()+"name:"+reference.get().getName()+"*****"+"value"+reference.get().getAmount());
            }
        }).start();

    }
}

执行结果

Customer3:com.project.domain.Customer@13f6c937name:Lucy*****value99
myClass.main-false--
com.project.domain.Customer@13f6c937name:Lucy*****value99
myClass.main-true--
com.project.domain.Customer@69b3d448name:Lily*****value99
Thread1-----------
Thread1:com.project.domain.Customer@69b3d448name:Lucy1*****value199
Thread2-----------
Thread2:com.project.domain.Customer@69b3d448name:Lucy2*****value299

根据结果看线程是安全的,thread1线程执行结束,才开始执行thread2.

三、应用拓展

除了AtomicReference可以保证多线程操作安全,Java库还有AtomicInteger、AtomicBoolean、AtomicLong保证多线程操作的安全性。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值