原子性

  • java.uitl.concurrent.atomic包中有很多类使用了很高效的机器级指令(而不是使用锁)来保证其它操作的原子性。例如,AtomicInterger类提供了方法incrementAndGetdecrementAndGet,它们分别以原子方式将一个整数自增或自减。
AtomicInteger atomicInteger = new AtomicInteger(1);
//以原子方式将一个整数自增1
int addAndGet = atomicInteger.incrementAndGet();
//以原子方式将一个整数自减1
int decrementAndGet = atomicInteger.decrementAndGet();
  • incrementAndGet方法以原子方式将AtomicLong自增,并返回自增后的值。也就是说,获得值,增1并设置然后生成新值的操作不会中断。可以保证即使是多个线程并发地访问同一个实例,也会计算并返回正确的值。
  • 如果希望完成更复杂的更新,就必须使用compareAndSet方法。例如,假设希望跟踪不同线程观察的最大值。
public static AtomicLong largest = new AtomicLong(5);
do{
  	oldValue = largest.get();
    long observed = 10l;
    newValue = Math.max(oldValue, observed);
}while (!largest.compareAndSet(oldValue,newValue));

compareAndSet结果

  • 如果另一个线程也在更新largest,就可能阻止这个线程更新。这样一来,compareAndSet会返回false,而不会设置新值。在这种情况下,循环会多次尝试,读取更新后的值,并尝试修改。最终,它会成功地用新值替换原来的值。
  • 实际上,可以提供一个lambda表达式更新变量
largest.updateAndGet(x->Math.max(x,observed));
或
largest.accumulateAndGet(observed,Math::max);
  • 还有getAndUpdate和getAndAccumulate方法返回原值
largest.getAndUpdate(x -> Math.max(x, observed));
或
largest.getAndAccumulate(observed,Math::max);
  • 如果有大量线程要访问相同的原子值,性能会大幅下降,因为乐观更新需要太多次重试。JavaSE 8提供了LongAdderLongAccumulator类来解决这个问题。LongAddr包括多个变量(加数),其总和为当前值。可以有多个线程更新不同的加数,线程个数增加时会自动提供新的加数。通常情况下,只有当所有工作都完成之后才需要总和的值,对于这种情况,这种方法会很高效。性能会显著的提升。
  • 代码结构如下
final LongAdder adder = new LongAdder();
        for(...)
            pool.submit(() -> {
                while (...){
                    ...
                    if(...)
                        //自增1,无返回值
                        adder.increment();
                }
            });
        ...
        long total = adder.sum();
  • LongAccumulator将这种思想推广到任意的累加操作。在构造器中,可以提供这个操作以及它的零元素。要加入新的值,可以调用accumulate。调用get来获得当前值。下面代码可以得到与LongAddr同样的效果。
LongAccumulator adder = new LongAccumulator(Long::sum, 0);
adder.accumulate(value);
  • 在内部,这个累加器包含a1,a2,…,an。每个变量初始化为零元素。
  • 调用accumulate并提供值v时,其中一个变量会以原子方式更新为ai = ai op v ,这里op是中缀形式的累加操作。这个例子中,调用accumulate会对某个i计算ai = ai + v。
  • get的结果是a1 op a2 op … op an。这就是累加器的总和:a1+a2+a3+…+an。
  • 另外DoubleAdderDoubleAccumulator也采用同样的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值