Java 的13个原子操作类

JDK1.5 以后开始提供java.util.concurrent.automic 包,该包中一共提供了13个类,用于简单、高效、线程安全的更新一个变量。给予类型,可以将这13个类分成以下四大部份:

原子更新基本类型类

automicBoolean:原子更新布尔类型
automicInteger:原子更新长整形
automicLong:原子更新整形
以上三个类提供方法基本一样如:
int addAndGet(int delta):以原子方式将输入的数值与实例中的值相加,并返回结果。
int getAndIncrement():以原子方式将当前值加1,返回自增前的值
实现:

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest{
    static AtomicInteger ai = new AtomicInteger(1);
    public static void main(String[] args){
        System.out.println(ai.getAndIncrement());

now,关注getAndIncrement的源码实现

public final int getAndIncrement(){
    for(;;){
        int current = get();
        int next = current+1;
        if(compareAndSet(current,next))
            return current;
    }
}
public final boolean compareAndSet(int expect,int update){
    return unsafe.compareAndSwapInt(this,valueoffset,expect,update);
}

第一步取得atmicInteger 里面存储的数值,第二步对当前数值加一,关键第三步,调用compareAndSet()方法来进行原子更新操作,如果当前数值等于current,说明没有被其他线程修改,完成更新,如果不等compareAndSet()方法返回false,程序重新for循环进行compareAndSet()操作。

原子更新数组

AtomicIntegerArray:原子更新数组里元素
AtomicLongArray:原子更新长整形数组元素
AtomicReferenceArray:原子更新引用类型数组里元素
以上几个类提供的方法基本一样:
int addAndGet(int i,int delta):以原子方式将输入值与索引对应元素i想加
boolean compareAndSet(int i,int expect,int update):但前值等于预期值,则原子方式更新。


public class AtomicIntegerArrayTest { 
    static int[] value = new int[] { 1, 2 }; 
    static AtomicIntegerArray ai = new AtomicIntegerArray(value); 
    public static void mian(String[] args){
        ai.getAndSet(0,3);
        System.out.println(ai.get(0)); 
        System.out.println(value[0]); 
    } 
}

原子更新引用类型

AtomicReference:原子更新引用类型
AtomicReferenceFieldUpdater:院子更新引用类型里的字段
AtomicMarkableReference:原子更新带有标记位的引用类型。
下面以AtomicReference为例进行说明:

import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceDemo {
    static class User{
        private String name;
        private int id;

        public User(String name,int id){
            this.name = name;
            this.id = id;
        }
        public String getName(){
            return name;
        }
       public void setName(String name) {
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
     }
    public static AtomicReference<user> ar = new AtomicReference<>();
    public static void main(String[] args){
        User user = new User('aa',11);
        ar.set(user);
        User newUser = new User("bb",22);
        ar.compareAndSet(user,newUser);
        System.out.println(ar.get().getName());//bb
        System.out.println(ar.get().getId());//22
    }
}

原子更新字段类

如果需要原子更新某个类的某个字段,就需要用到原子更新字段类,可以使用以下几个类:
AtomicIntegerFieldUpdater:原子更新整型字段
AtomicLongFieldUpdater:原子更新长整型字段
AtomicStampedReference:原子更新带有版本号的引用类型。

要想原子更新字段,需要两个步骤:
1.每次必须使用newUpdater创建一个更新器,并且需要设置想要更新的类的字段
2.更新类的字段(属性)必须为public volatile

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterDemo {
    //创建一个原子更新器
    private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater (User.class,"old");
    public static void main(String[] args){
        User user = new User("Tom",15);
        //原来的年龄  15
        System.out.println(atomicIntegerFieldUpdater.getAndIncrement(user));
        //现在的年龄 16
        System.out.println(atomicIntegerFieldUpdater.get(user));
    }
    static class User{
        private String name;
        public volatile int old;

        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getOld() {
            return old;
        }

        public void setOld(int old) {
            this.old = old;
        }
    }
}


相关底层实现

JDK中有一个类Unsafe,它提供了硬件级别的原子操作,例如获取数据的内存地址偏移等等,所以这个类对开发人员来说是不安全的。而这个CAS就在这个Unsafe中。 到这里只需要知道java底层通过Unsafe这个工具类来完成原子操作,UnSafe中大部分方法都是本地方法,与操作系统关系密切。

CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时(条件),将内存值修改为B并返回true,否则条件不符合返回false。

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    //获得unsafe实例
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //存放变量value的内存偏移
    private static final long valueOffset;

    static {
        try {
            //通过unsafe获得value的内存偏移
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    //volatile修饰的,保证了多线程之间看到的value值是同一份,后面会分析
    private volatile int value;
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值