6.JAVA线程同步机制:原子变量类

原子变量类 (Atomics)是基于CAS实现的能够保障对共享变量进行read-modify-write更新操作的原子性和可见性的一组工具类。这里所谓的read-modify-write更新操作,是指对共享变量的更新不是一个简单的赋值操作,而是变量的新值依赖于变量的旧值,例如自增操作 “count++”。由于volatile无法保障自增操作的原子性,而原子变量类的内部实现通常借助一个volatile变量并保障对该变量的read-modify-write更新操作的原子性,因此它可以被看作增强型的volatile变量。原子变量类一共有12个,可以被分为4组,如下表所示 :

  • AtomicLong类继承自Number类,其内部维护了一个long型volatile变量。AtomicLong类对外暴露了相关方法用于实现针对该volatile变量的自增(自减)操作,这些操作是基于CAS实现的原子性操作。AtomicLong 类可以被看作一个增强型的volatile long变量:调用 AtomicLong的get()方法相当于读取一个volatile变量;调用AtomicLong的incrementAndGet()等实现自增、自减的方法相当于写volatile变量,与直接写volatile变量所不同的是这些方法所执行的操作具有原子性 。

  • Atomiclnteger的使用方法类似于AtomicLong,不再赘述 。

  • AtomicBoolean类如同其他原子操作类一样,它们是要实现read-modify-write操作的原子性 。

  • 即使采用volatile关键字修饰数组变量,也无法保障对相应元素的读、写操作的可见性和原子性。为此,Java专门引入了AtomiclntegerArrayAtomicLongArrayAtomicReferenceArray这3个类。

  • AtomicReference类的主要功能可以理解为对引用型变量的有条件更新:更新引用变量时确保该变量的确是我们要修改的那个,即该变量没有被其他线程修改过。

  • CAS实现原子操作背后的一个假设是:共享变量的当前值与当前线程所提供的旧值相同,我们就认为这个变量没有被其他线程修改过。实际上,这个假设不一定总是成立。例如,对于共享变量V,当前线程看到它的值为A的那一刻,其他线程已经将其值更新为B, 接着在当前线程执行CAS的时候该变量的值又被其他线程更新为A, 那么此时我们是否认为变量V的值没有被其他线程更新过呢,或者说这种结果是否可以接受呢?这就是 ABA 问题,即共享变量的值经历了A---->B---->A 的更新。规避 ABA 问题也不难,那就是为共享变量的更新引入一个修订号(也称时间戳)。每次更新共享变量时相应的修订号的值就会被增加1。也就是说,我们将共享变量V的值”扩展”成一个由变量实际值和相应的修订号所组成的元组([共享变量实际值,修订号])。于是,对于初始实际值为A的共享变量V,它可能经历这样的变化更新:[A,0]---->[B,1]–>[A,2]。这里,虽然变量V的实际值仍然经历了A---->B---->A的更新,但是由于每次变量 的更新都导致了相应修订号的增加,我们依然能够准确地判断究竟变量的值是否被其他线程修改过。AtomicStampedReference类就是基于这种思想而产生的 。

  • 字段更新器(AtomiclntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater)这3个类相对来说更加底层一点儿,可以将其理解为对CAS的一种封装,而原子变量类中的其他类都可以利用这几个类来实现 。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值