java 累计 安全_为什么AtomicXXX是线程安全的累计计数

effective java 第66条内容说到,累计计数i++同步问题

一种是用sync修饰符进行同步操作

另一种是使用AtomicXXX变量,如AtomicLong 的 getAndIncrement方法

好奇AtomicLong的实现,原以为也是进行同步锁操作实现的原子性。

发现源码并不是这样做的,而是使用了native方法unsafe,改方法只能在授信的代码中实例化如jdk内。

代码如下

public final long getAndIncrement() {

while (true) {

long current = get();

long next = current + 1;

if (compareAndSet(current, next))

return current;

}

}

compareAndSet

public final boolean compareAndSet(long expect, long update) {

return unsafe.compareAndSwapLong(this, valueOffset, expect, update);

}

可以发现当进行累加操作时,第一时间没有进行对变量的更改操作

而是将累加结果保存,通过compareAndSet方法对变量更改,

使用unsafe CAS方法判断当前值与要累加的值expect对比,如果两个变量是同一个,则进行更改操作update->当前值,否则返回false CAS存在一个ABA问题,即当判断值A是否被修改前,该值被其他线程修改成了B,然后又被修改回了A,那么CAS仍然认为该值是没有被修改过的,进行赋值操作

而getAndIncrement原理就是,不断的loop循环判断,当前值有没有在累加操作前被其他线程修改了,如果没改就赋值,改了就重新累加,再判断赋值。从而形成了类似同步的机制。保证变量的原子性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值