JUC中Atomic包分析

并发场景中,为了保证线程安全,也就是临界区代码按照我们所想的时序运行,需要进行加锁,也就是同步控制,但是有很多情况,不需要我们自己进行同步控制,而是可以使用java自带的并发组件,本文主要讲Atomic包中提供原子操作的类,接下来我们依次分析。

AtomicInteger

相信应该是用的最多的原子操作类了,它的主要作用是进行int类型变量的包装,让变量的操作都是线程安全。如何实现呢?最容易想到的应该是每个方法进行加锁控制,这是没问题的。但juc中并非这种方式,而是使用了volatile进行可见性控制和失败重试的CAS操作来保证成功的原子性,这也是乐观锁一种实现。
关于CAS操作:每次修改数据时,都会比较数据的原值,如果原值没有改变,代表没有其他线程进行并发修改,可以安全更新,如果原值改变了,代表有线程成功修改了此值,则此次更新失败。
AtomicInteger提供了很多有用的方法,当然我不会一一分析,就说说常用的,在源码基础是进行注释。

    /**因为value变量是用volatile修饰的所以get永远是获取的最新值*/
    public final int get() {
        return value;
    }
     //原理同get()
     public final void set(int newValue) {
        value = newValue;
    }
    /**获取原值并且设置新增,这个方法应该用的比较少,因为这个原值可能已经不是我们希望的了,但是这步操作会成功的改变原值*/
     public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

    /**这就是cas的实现,对先查询后更新操作进行原子性保障,原理是直接通过内存偏移量进行内存最新数据的比较,如果内存中的数据是所希望的,表示没有其他的线程进行修改,那么就可以进行正确的更新*/
public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    /**此方法应该是最常用的,这是线程安全的i++操作,并返回原值*/
     public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }
   //如果i++后需要返回新值,则是下面的
   public final int incrementAndGet() ;
 //  同理i--操作也是提供两个
 public final int getAndDecrement();//返回原值
 public final int decrementAndGet();//返回新增
 /**那么有i++,那么如果i+n呢,同样也有两个*/
 public final int getAndSet(int newValue);//返回旧值
 public final int addAndGet(int delta);//返回新值

总的来说AtomicInteger,就是线程安全的int类型,同时提供了很多上面的常见操作,合理的使用,可以在并发编程中减轻很多的工作。

AtomicBoolean

实现的原理和AtomicInteger一样,底层还是用int类型,并不是boolean,就不复制源码了,简单的说下常用的方法:

方法描述
boolean get()获取最新值
set(boolean newValue)设置成newValue
boolean compareAndSet(boolean expect, boolean update)cas设值
boolean getAndSet(boolean newValue)设置newValue并返回原值

如果仅仅是为了赋值操作,那么也没有必要AtomicBoolean,因为jvm虚拟机规范中规定,除了long和double类型外其他的任何类型赋值操作都是原子的,只需进行volatile修饰,保证可见性就能对单一的赋值操作进行同步保证。

AtomicLong

AtomicLong的实现可以说和AtomicInteger的一模一样,同样那些操作,不过包装的是long型罢了,这里就不细细分析了。

AtomicReference

AtomicReference和AtomicBoolean的使用可以说一模一样,只不过包装的是对象的引用,需要注意的是,对象的比较操作不是通过==或者equals,而是比较的引用的的指针位置。

其他

其他的数组的实现,原理都一样,cas操作,AtomicIntegerArray和AtomicInteger不同的地方在于,操作的方法需要带上数组元素的位置,也就是索引,AtomicLongArray,AtomicReferenceArray同样可以类比AtomicLong和AtomicReference,这里就不详细说明了。

总之,在新的并发场景中,还是尽量使用线程安全的现有组件,安全可靠且规范。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值