Java|伙计,提高自己的并发技能,从锁优化开始!( 四 )

CAS操作一个变量时 , 只有一个会胜出 , 并成功更新 , 其他均会失败 。 失败的线程不会被挂起 , 仅是被告知失败 , 并且允许再次尝试 , 当然也允许失败的线程放弃操作 。
线程安全整数(AtomicInteger)AtomicInteger是在 JDK并发包中的atomic 中的 , 可以把它看作一个整数 , 与Integer不同的是 , 它是可变的 , 并且是线程安全的 。 对其进行修改等任何操作都是用 CAS 指令进行的 。 下面是AtomicInteger 的常用方法:
就内部实现上来说 , AtomicInteger中保存了一个核心字段:
使用示例:可以看出 , 在多线程的情况下 , AtomicInteger是保证线程安全的 。
无锁的对象引用(AtomicReference)AtomicReferenceAtomicInteger非常相似 , 不同之处就在于AtomicInteger是对整数的封装 , 而AtomicReference是对普通对象的引用 , 也就是它可以保证你在修改对象引用时的线程安全性 。
通常情况下线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望值是否一致是正确的 。 但是有一种特殊的情况就是:当你获取对象当前数据后 , 在准备修改被新值前 , 对象的值被其他线程连续修改了两次 , 最后一次修改为旧值 , 这个时候线程在不知情的情况下 , 又对这个数据重新赋值 。 下图说明为例:



带有时间戳的对象引用(AtomicStampedReference)AtomicReference无法解决上面的问题是因为 , 对象在修改成成中丢失了状态信息 , 因此我们只要能够记录对象在修改过程中的状态值 , 就可以很好的解决对象被反复修改的导致线程无法正确判断对象状态的问题 。
AtomicStampedReference它内部不经维护了对象值 , 还维护了一个时间戳 , 当AtomicStampedReference被修改的时候 , 除了更新数据本身外 , 还必须要更新时间戳 。 当AtomicStampedReference设置对象值时 , 对象值及时间戳都必须满足期望值 , 写入才会成功 , 因此 , 即使对象之被反复读写 , 写回原值 , 只要时间戳发生变化 , 就不能正确写入 。



推荐阅读