原子类AtomicInteger

本文详细介绍了Java中Atomic包的功能及其实现原理,重点剖析了AtomicInteger类的构造函数、compareAndSet方法、getAndSet方法及i++的实现过程,并通过实例展示了如何使用AtomicInteger实现随机数字生成器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概述

Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。
原子类其内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile和native方法(同步的工作更多的交给了硬件),从而避免了synchronized的高开销,执行效率大为提升
虽然基于CAS的线程安全机制很好很高效,但要说的是,并非所有线程安全都可以用这样的方法来实现,这只适合一些粒度比较小,型如计数器这样的需求用起来才有效,否则也不会有锁的存在了
在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。

2.代码详解

现在我们来分析一下Atomic包中AtomicInteger的源代码,其它类的源代码在原理上都比较类似。

有参构造函数:从构造函数函数可以看出,数值存放在成员变量value中;
成员变量value声明为volatile类型,说明了多线程下的可见性,即任何一个线程的修改,在其它线程中都会被立刻看到

public AtomicInteger(int initialValue) { 
value = initialValue;
}

compareAndSet方法(value的值通过内部this和valueOffset传递)
这个方法就是最核心的CAS操作
接收2个参数,一个是期望数据(expected),一个是新数据(new);如果atomic里面的数据和期望数据一致,则将新数据设定给atomic的数据,返回true,表明成功;否则就不设定,并返回false。

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

getAndSet方法,在该方法中调用了compareAndSet方法
本质是get( )操作,然后做set( )操作。尽管这2个操作都是atomic,但是他们合并在一起的时候,就不是atomic
如果在执行if(compareAndSet(current,newValue)之前其它线程更改了value的值,那么导致value的值必定和current的值不同,compareAndSet执行失败,只能重新获取value的值,然后继续比较,直到成功。

   public final int getAndSet(int newValue) {
		 for (;;) {
			  int current = get();
		  if (compareAndSet(current, newValue))
   		 return current;
	  }
	}

i++的实现
一般来说自增和自减都不是原子操作,其中包含有3个操作步骤:第一步,读取i;第二步,加1或减1;第三步,写回内存
为了实现原子性,必须在for循环中比较值value是否被修改

public final int getAndIncrement() {
for (;;) {
  int current = get();
  int next = current + 1;
  if (compareAndSet(current, next))
    return current;
  }
}

++i的实现

public final int incrementAndGet() {
for (;;) {
  int current = get();
  int next = current + 1;
  if (compareAndSet(current, next))
    return next;
    }
}

实例:使用AutomicInteger实现随机数字生成器

puclic class AutomicRandom{
private AutomicInteger seed;
AutomicRandom(int seed){
    this.seed = new AutomicInteger(seed);
}
public int nextInt(){
    while(true){
        int s = seed.get();
        int nextSeed = calculateNext(s);
        if(seed.compareAndSet(s,nextSeed)){ 
             //对比新旧数据是否一致,一致则设置
            //新的数字成功设置到原子类对象里面
            int remainder = s % n;
            return remainder > 0 ? remainder : remainder + n;
        }
    }
}
  1. 总结
    在中低程度的竞争下,原子类提供更高的伸缩性;在高强度的竞争下,锁能更好的帮助我们避免竞争。(来自《并发编程实战》)
    所以,我们要视情况而定,若资源竞争规模不大,控制粒度较小,使用原子类比使用锁更好,能提高效率与性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值