并发读源码——AtomicInteger/AtomicLong/AtomicStampedReference

本文主要是介绍并发读源码——AtomicInteger/AtomicLong/AtomicStampedReference,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1. AtomicInteger描述
  • 2. 源码解析
  • 3. AtomicInteger演示示例
  • 4. 多线程用法

1. AtomicInteger描述

AtomicInteger从名字上看是操作Integer整数的,但Integer是线程不安全的,AtomicInteger是线程安全的。AtomicInteger的作用可以把两个Integer对象的加减乘除等操作变成一个原子操作,如果对Integer的操作不用AtomicInteger,也可以选择用synchronized锁住两个Integer对象的操作,synchronized是重量级锁,悲观锁,资源开销大,而AtomicInteger中的操作方法采用的轻量级锁,乐观锁,下面会进行分析。

2. 源码解析

AtomicInteger的原理就是运用了乐观锁
悲观锁与乐观锁区别:

  • 悲观锁:在并发操作之前认为冲突概率比较大,读操作之前就上锁。比如synchronized关键字
  • 乐观锁:在并发操作之前认为冲突的概率比较小,读操作不上锁,等到写操作时,再判断数据在此期间是否被修改了,如果数据被修改了,则就把数据重新读出来,重新执行该过程;如果原始数据没被修改,就直接把新值写回去。

AtomicInteger的乐观锁是通过Unsafe下的compareAndSwapInt方法执行的,AtomicInteger是通过乐观锁中的自旋锁方式获取锁的(自旋锁:不放弃CPU,空转,不停的重试,典型的就是通过for进行循环)。

package java.util.concurrent.atomic;
import java.util.function.IntUnaryOperator;
import java.util.function.IntBinaryOperator;
import sun.misc.Unsafe;/*** An {@code int} value that may be updated atomically.  See the* {@link java.util.concurrent.atomic} package specification for* description of the properties of atomic variables. An* {@code AtomicInteger} is used in applications such as atomically* incremented counters, and cannot be used as a replacement for an* {@link java.lang.Integer}. However, this class does extend* {@code Number} to allow uniform access by tools and utilities that* deal with numerically-based classes.** @since 1.5* @author Doug Lea
*/
public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();/*valueOffset是下面定义的value在AtomicInteger类内存的偏移量,通过这个偏移量可以定位value的值,下面读写AtomicInteger 对象中的值都是valueOffset进行操作的*/private static final long valueOffset;/*因为value是private类型的,是不能直接获取的,因此通过反射形式获取value变量,然后通过java的native方法unsafe.objectFieldOffset获取value相对AtomicInteger类的内存偏移量*/static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*初始化时指定value的值*/public AtomicInteger(int initialValue) {value = initialValue;}/*默认初始化方式,value值默认为0,因为value是int类型的*/public AtomicInteger() {}/*获取value值*/public final int get() {return value;}/*修改value值,因为value是volatile类型的,会立即把value中的值刷入主内存,其它线程可以看到修改*/public final void set(int newValue) {value = newValue;}/*lazySet方法现实中很少用,不会立即把value刷入主内存,但最终会刷值,保证最终一致性*/public final void lazySet(int newValue) {unsafe.putOrderedInt(this, valueOffset, newValue);}/*先获取value的值,然后修改value值为新值newValue,整个动作是原子性的,通过unsafe.getAndSetInt方式实现*/public final int getAndSet(int newValue) {return unsafe.getAndSetInt(this, valueOffset, newValue);}/*封装了Unsafe中compareAndSwapInt的native函数,compareAndSet有两个参数,expect指变量的旧值,是读出来的值,写回去的时候希望没有没其他线程修改,所以是expect;第二个参数是update,值变量的新值,修改过的,希望写入的value值。当expect等于变量当前值时,说明在修改期间没有其他线程对此变量进行修改,所以可以成功写入,变量更新为update,返回true,否则返回false*//*compareAndSwapInt有4个参数,第一个参数是AtomictInteger对象,第二个是成员变量value相对AtomictInteger类的内存偏移量,expect和update保持不变*//*** 如果内存中的value成员变量值等于expect的值,就把update值更新到value中,compareAndSwapInt方法是原子的,先比较,如果相等就直接更新(根据value在AtomicInteger中内存偏移量valueOffset来更新)*/public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}/*** weakCompareAndSet方法与compareAndSet类似,但weakCompareAndSet不会插入内存屏障,不能保障volatile的原子性*/public final boolean weakCompareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}/*** 先获取value成员变量的值,然后对value增加1*/public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}/*** 先获取value成员变量的值,然后对value减1public final int getAndDecrement() {return unsafe.getAndAddInt(this, valueOffset, -1);}/*** 先获取value成员变量的值,然后把delta加到value上*/public final int getAndAdd(int delta) {return unsafe.getAndAddInt(this, valueOffset, delta);}/*** 先对成员变量value增加1,然后把修改后的值更新到value中*/public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}/*** 先对成员变量value减1,然后把修改后的值更新到value中*/public final int decrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, -1) - 1;}/*** 先对成员变量value增加delta,然后把修改后的值更新到value中*/public final int addAndGet(int delta) {return unsafe.getAndAddInt(this, valueOffset, delta) + delta;}/*** 先获取value的值赋值给prev,然后对prev执行功能函数updateFunction,把结果next更新到value中*//*该方法用到了自旋锁,当prev的值等于内存中的value值时,才会把next的值更新到value中,否则该方法会进行自旋,即一遍遍的获取锁重试,当prev的值等于内存中的value值时进行更新*/public final int getAndUpdate(IntUnaryOperator updateFunction) {int prev, next;do {prev = get();next = updateFunction.applyAsInt(prev);} while (!compareAndSet(prev, next));return prev;}/*** 该方法与上面方法原理相同,只是先更新后,再获取value值*/public final int updateAndGet(IntUnaryOperator updateFunction) {int prev, next;do {prev = get();next = updateFunction.applyAsInt(prev);} while (!compareAndSet(prev, next));return next;}/*** 该方法与上面方法原理相同,只是功能函数变为了IntBinaryOperator,执行两个整数返回一个整数;* 先获取value值,然后功能函数执行后的结果更新到value中*/public final int getAndAccumulate(int x,IntBinaryOperator accumulatorFunction) {int prev, next;do {prev = get();next = accumulatorFunction.applyAsInt(prev, x);} while (!compareAndSet(prev, next));return prev;}/*** 该方法与上面函数类似,只是先更新value值,然后获取返回更新后的value值*/public final int accumulateAndGet(int x,IntBinaryOperator accumulatorFunction) {int prev, next;do {prev = get();next = accumulatorFunction.applyAsInt(prev, x);} while (!compareAndSet(prev, next));return next;}/*** 把value值转化为String 类型*/public String toString() {return Integer.toString(get());}/***获取value成员变量值*/public int intValue() {return get();}/*** 把value值转化为long类型*/public long longValue() {return (long)get();}/*** 把value值转化为float类型*/public float floatValue() {return (float)get();}/*** 把value值转化为double类型*/public double doubleValue() {return (double)get();}}

3. AtomicInteger演示示例

package com.lzj.atomic;import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;public class AtomicIntegerDemo2 {public static void main(String[] args) {get();set();getAndSet();getAndIncrement();getAndDecrement();getAndAdd();incrementAndGet();decrementAndGet();addAndGet();getAndUpdate();updateAndGet();getAndAccumulate();accumulateAndGet();}/*测试AtomicInterger.get方法*/public static void get() {AtomicInteger at = new AtomicInteger(10);int value = at.get();System.out.println("get() : " + value);}/*测试AtomicInteger.get方法*/public static void set() {AtomicInteger at = new AtomicInteger(10);at.set(20);System.out.println("set()" + at.get());}/*测试AtomicInteger.getAndSet*/public static void getAndSet() {AtomicInteger at = new AtomicInteger(10);int oldValue = at.getAndSet(20);System.out.println("getAndSet : " + at.get());System.out.println("getAndSet : " + oldValue);}/*测试AtomicInteger.getAndIncrement*/public static void getAndIncrement() {AtomicInteger at = new AtomicInteger(10);at.getAndIncrement();System.out.println("getAndIncrement : " + at.get());}public static void getAndDecrement() {AtomicInteger at = new AtomicInteger(10);at.getAndDecrement();System.out.println("getAndDecrement : " + at.get());}/*测试AtomicInteger.getAndAdd*/public static void getAndAdd() {AtomicInteger at = new AtomicInteger(10);at.getAndAdd(5);System.out.println("getAndAdd : " + at.get());}/*测试AtomicInteger.incrementAndGet*/public static void incrementAndGet() {AtomicInteger at = new AtomicInteger(10);int current = at.incrementAndGet();System.out.println("incrementAndGet() : " + at.get());System.out.println("incrementAndGet() : " + current);}/*AtomicInteger.decrementAndGet*/public static void decrementAndGet() {AtomicInteger at = new AtomicInteger(10);int current = at.decrementAndGet();System.out.println("decrementAndGet() : " + at.get());System.out.println("decrementAndGet() : " + current);}/*测试AtomicInteger.addAndGet*/public static void addAndGet() {AtomicInteger at = new AtomicInteger(10);int current = at.addAndGet(10);System.out.println("addAndGet() : " + at.get());System.out.println("current : " + current);}/*测试AtomicInteger.getAndUpdate*/public static void getAndUpdate() {AtomicInteger at = new AtomicInteger(11);IntUnaryOperator updateFunction = x -> x/2;int old = at.getAndUpdate(updateFunction);System.out.println("getAndUpdate() : " + at.get());System.out.println("getAndUpdate() : " + old);}/*测试AtomicInteger.updateAndGet*/public static void updateAndGet() {AtomicInteger at = new AtomicInteger(11);IntUnaryOperator updateFunction = x -> x/2;int current = at.updateAndGet(updateFunction);System.out.println("updateAndGet() : " + at.get());System.out.println("updateAndGet() : " + current);}/*测试AtomicInteger。getAndAccumulate*/public static void getAndAccumulate() {AtomicInteger at = new AtomicInteger(11);IntBinaryOperator accumulatorFunction = (x,y) -> x / y;int old = at.getAndAccumulate(2, accumulatorFunction);System.out.println("getAndAccumulate() : " + at.get());System.out.println("getAndAccumulate() : " + old);}/*测试AtomicInteger.accumulateAndGet*/public static void accumulateAndGet() {AtomicInteger at = new AtomicInteger(11);IntBinaryOperator accumulatorFunction = (x,y) -> x / y;int current = at.accumulateAndGet(2, accumulatorFunction);System.out.println("accumulateAndGet() : " + at.get());System.out.println("accumulateAndGet() : " + current);}
}

执行结果如下

get() : 10
set()20
getAndSet : 20
getAndSet : 10
getAndIncrement : 11
getAndDecrement : 9
getAndAdd : 15
incrementAndGet() : 11
incrementAndGet() : 11
decrementAndGet() : 9
decrementAndGet() : 9
addAndGet() : 20
current : 20
getAndUpdate() : 5
getAndUpdate() : 11
updateAndGet() : 5
updateAndGet() : 5
getAndAccumulate() : 5
getAndAccumulate() : 11
accumulateAndGet() : 5
accumulateAndGet() : 5

4. 多线程用法

package com.lzj.atomic;import java.util.concurrent.atomic.AtomicInteger;public class AtomicDemo1 {public static AtomicInteger count = new AtomicInteger(10);public void add() {count.getAndIncrement();System.out.println("thread1 : " + count);}public void dec() {System.out.println("thread2 : " + count);count.getAndDecrement();}public static void main(String[] args) {AtomicDemo1  atomicDemo1 = new AtomicDemo1();Runnable run1 = new Runnable() {public void run() {atomicDemo1.add();System.out.println("thread1 : " + atomicDemo1.count);}};Runnable run2 = new Runnable() {public void run() {atomicDemo1.dec();System.out.println("thread2 : " + atomicDemo1.count);}};Thread thread1 = new Thread(run1);Thread thread2 = new Thread(run2);thread1.start();thread2.start();}
}

另外,AtomicLong与AtomicInteger除了value的类型不一样,其它几乎都类似。
AtomicStampedReference与AtomicInteger源码基本类似,只是AtomicInteger用来处理整数类型,通过自旋锁的方式利用compareAndSwapInt来解决CAS问题;而AtomicStampedReference用来处理对象,通过自旋锁的方式利用compareAndSwapObject来解决CAS问题,关于AtomicStampedReference的详解参考AtomicStampedReference

这篇关于并发读源码——AtomicInteger/AtomicLong/AtomicStampedReference的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/994179

相关文章

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL