【连载 09】atomic包原子类
2.4 atomic包原子类
java.util.concurrent.atomic包提供了一组用于实现原子操作的类。这些类可以用于在多线程环境中执行线程安全的、不可中断的原子操作。原子操作类提供了一种稳定可靠的方式执行原子类操作,而不是使用锁实现。原子操作类适用于各种并发场景,特别在是高并发场景种,原子操作类性能表现非常突出。
atomic包下面的功能类,性能测试使用到的只有4种:分别是AtomicBoolean、AtomicInteger、AtomicLong和LongAdder。
对于前三种,相信你会有一种眼熟的感觉,都有对应的Java基础数据类型,使用方式也很相似,把Java操作符换成了方法实现取值和赋值功能。下面逐个介绍几位主角。
1. AtomicBoolean
AtomicBoolean类常用于多线程环境种对Boolean值的操作。使用者可以直接对AtomicBoolean对象的值进行修改,而不需要借助锁和synchronized关键字。下面是AtomicBoolean常用的功能。
- public AtomicBoolean(boolean initialValue):构造方法,有无参构造方法,等效于该方法initialValue = false。
- get():获取Boolean值的方法,返回boolean值。
- set(boolean newValue):设置新的boolean值。
- getAndSet(boolean newValue):获取当前值,并设置新的值。
- compareAndSet(boolean expect, boolean update):若当前值等于预期,则更新值,返回true。否则不更新,返回false。
AtomicBoolean在性能测试中,通常用来标记线程状态,控制线程启动和停止;资源初始化、重置的状态标记,减少线程间竞争;还可以用来控制并发,限制同时执行某个操作的线程数。
2. AtomicInteger
AtomicInteger类常用于对整数值的执行原子操作。使用者可以对AtomicInteger对象进行线程安全的加、减操作,同样的不需要锁和synchronized。下面是AtomicInteger常用功能。
- public AtomicInteger(int initialValue):构造方法,有无参构造方法,等效于该方法initialValue = 0。
- get():获取整数值的方法,返回整数值。
- set(int newValue):设置整数值。
- getAndSet(int newValue):获取当前值,并重新新的值。
- getAndIncrement() 和 getAndDecrement():获取当前值,并且对当前值进行加一和减一操作。同胞兄弟incrementAndGet()和decrementAndGet(),区别在于这两个方法先进行赋值操作后获取值,类似与 i++ 和 ++i的区别。
- addAndGet(int delta):在当前值基础上增加指定量(可以是负值),并获取新值。
- compareAndSet(int expect, int update):若当前值等于预期值,则重新赋值,返回true,否则不更新值,返回false。
- AtomicInteger主要应用在多线程场景中,计数和状态控制。在性能测试中,通常用来进行数据的计算,例如统计执行任务的数量、用户对某商品的消费总额等。
3. AtomicLong
AtomicLong功能跟AtomicInteger一样,区别在于AtomicLong可以表达的整数类型范围更广。两者所能处理的整数范围预期对应基础数据类型所能表示整数类型范围一样。
4. LongAdder
LongAdder功能与AtomicLong、AtomicInteger一模一样,能处理整数值范围与AtomicLong一致。区别在于LongAdder在高并发计数场景中,性能表现更好。原因在于LongAdder使用了分段锁来降低线程竞争,这个设计思路跟ConcurrentHashMap一致。如果你将来遇到类似场景,可以阅读这两个类的源码寻找设计灵感。下面介绍一下LongAdder的常用功能。
- LongAdder():构造方法,只此一家,默认值为0。
- add(long x):将当前值增加固定量(可以为负)。
- increment()和decrement():将当前值自增一和自减一,等效于add(1L)和add(-1L)。
- sum():获取当前累计值,由于采取了分段设计,所以方法名是求和(sum)。
- reset():重置当前对象,回复默认值0。
- sumThenReset():获取当前值,并重置。
LongAdder使用场景跟前两者基本重合,如果你需要进行高并发计数、大规模数据聚合操作,优先考虑LongAdder实现该功能。
对于高并发并没有一个严格的规范,笔者提供一个数据仅供参考:在500线程并发场景下:LongAdder优势比较明显;在200 ~ 300并发场景中,LongAdder略有优势;在更低的并发中,两者性能无明显差异。
如果在工作中,你仍然无法决断,后面会讲到Java微基准测试工具JMH,可以帮助你在实际场景中做出明智的选择。
书的名字:从 Java 开始做性能测试 。
如果本书内容对你有所帮助,希望各位不吝赞赏,让我可以贴补家用。赞赏两位数可以提前阅读未公开章节。我也会尝试制作本书的视频教程,包括必要的答疑。
FunTester 原创精华
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2024-01-03 利用虚拟线程重写自定义异步功能