AtomicInteger使用一定要注意越界问题

背景

最近新接手了一个项目,在阅读项目代码的时候发现了一个很严重的问题:所有使用到的AtomicInteger类型变量都没有处理越界问题。当然,并不是所有的AtomicInteger类型变量都需要注意其边界问题,但是如果其用在生成各种Id的时候就一定需要注意其边界问题。

项目中的AtomicInteger变量就被用来生成一个资源的Id的后四位,然后和其他字符串拼成一个完整的Id。但是其只使用了AtomicInteger的incrementAndGet方法不断的增加,并没有注意到如果AtomicInteger增加到了2147483647(Integer.MAX_VALUE)再加一,AtomicInteger的值会变成负数-2147483648(Integer.MIN_VALUE)。如果不对其作出处理,当资源数目不断累积超过最大值变成负数的时候,最后产生的Id中会带有一个“-”,这将带来灾难性的后果。

解决方案

为了解决这个问题,在网上查阅了一些博客之后,找到了AtomicInteger控制边界问题的一种最佳实践。其可以在AtomicInteger变量达到最大值的时候,转为零重新开始计数。并保证AtomicInteger在多线程环境下的原子性。代码如下,compareAndSet方法讲解见下面。

private final AtomicInteger i;
public final int incrementAndGet() {
    int current;
    int next;
    do {
        current = this.i.get();
        next = current >= 2147483647?0:current + 1;
    } while(!this.i.compareAndSet(current, next));

    return next;
}

public final int decrementAndGet() {
    int current;
    int next;
    do {
        current = this.i.get();
        next = current <= 0?2147483647:current - 1;
    } while(!this.i.compareAndSet(current, next));

    return next;
}

compareAndSet

AtomicInteger类的compareAndSet方法是会去调用Unsafe类的compareAndSwapInt方法,而compareAndSwapInt方法是一个本地方法,这里不再展开,简单介绍下compareAndSet方法。

public final boolean compareAndSet(int expect, int update) {
   return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

compareAndSet方法的功能其实很简单,当expect值和该时刻AtomicInteger对象在内存中的值一样时,将内存中的值更新为update。这也是AtomicInteger能保证原子性的核心。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值