原子操作类

原子操作类

  原子性这个概念,在多线程编程里是一个老生常谈的问题。 所谓的原子性表示一个或者多个操作,要么全部执行完, 要么一个也不执行。不能出现成功一部分失败一部分的情 况。在多线程中,如果多个线程同时更新一个共享变量,可能 会得到一个意料之外的值。比如 i=1 。A 线程更新 i+1 、 B 线程也更新 i+1。通过两个线程并行操作之后可能 i 的值不等于 3。而可能等 于 2。因为 A 和 B 在更新变量 i 的时候拿到的 i 可能都是 1 这就是一个典型的原子性问题。

  多线程里面,要实现原子性,有几 种方法,其中一种就是加 Synchronized 同步锁。 而从 JDK1.5 开始,在 J.U.C 包中提供了 Atomic 包,提供了 对于常用数据结构的原子操作。它提供了简单、高效、以 及线程安全的更新一个变量的方式。

J.U.C 中的原子操作类

  由于变量类型的关系,在 J.U.C 中提供了 12 个原子操作的 类。这 12 个类可以分为四大类。

1. 原子更新基本类型 AtomicBoolean、AtomicInteger、AtomicLong

2. 原子更新数组 AtomicIntegerArray 、 AtomicLongArray 、 AtomicReferenceArray

3. 原子更新引用 AtomicReference 、 AtomicReferenceFieldUpdater 、 AtomicMarkableReference(更新带有标记位的引用类 型)

4. 原子更新字段 AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、 AtomicStampedReference

AtomicInteger 原理分析

  接下来,我们来剖析一下 AtomicInteger 的实现原理,仍 然是基于我们刚刚在前面的案例中使用到的方法作为突破 口

getAndIncrement

  getAndIncrement 实际上是调用 unsafe 这个类里面提供 的方法, Unsafe 类我们前面在分析 AQS 的时候讲过,这个类相当 于是一个后门,使得 Java 可以像 C 语言的指针一样直接操 作内存空间。当然也会带来一些弊端,就是指针的问题。 实际上这个类在很多方面都有使用,除了 J.U.C 这个包以 外,还有 Netty、kafka 等等 这个类提供了很多功能,包括多线程同步(monitorEnter)、 CAS 操 作 (compareAndSwap) 、线程的挂起和恢复 (park/unpark)、内存屏障(loadFence/storeFence) 内存管理(内存分配、释放内存、获取内存地址等.)

public final int getAndIncrement() {
 return unsafe.getAndAddInt(this,
valueOffset, 1);
}

valueOffset,也比较熟了。通过 unsafe.objectFieldOffset() 获取当前 Value 这个变量在内存中的偏移量,后续会基于 这个偏移量从内存中得到value的值来和当前的值做比较, 实现乐观锁

private static final long valueOffset;
static {
 try {
 valueOffset = unsafe.objectFieldOffset

(AtomicInteger.class.getDeclaredField("value")
);
 } catch (Exception ex) { throw new 
Error(ex); }
}

getAndAddInt

  通过 do/while 循环,基于 CAS 乐观锁来做原子递增。实 际上前面的 valueOffset 的作用就是从主内存中获得当前 value 的值和预期值做一个比较,如果相等,对 value 做递 增并结束循环。

public final int getAndAddInt(Object var1, long
var2, int var4) {
 int var5;
 do {
 var5 = this.getIntVolatile(var1, var2);
 } while(!this.compareAndSwapInt(var1, var2,
var5, var5 + var4));
 return var5;
}

get 方法

  get 方法只需要直接返回 value 的值就行,这里的 value 是 通过 Volatile 修饰的,用来保证可见性。

public final int get() {
 return value;
}

其他方法

  AtomicInteger 的实现非常简单,所以我们可以很快就分析 完它的实现原理,当然除了刚刚分析的这两个方法之外, 还有其他的一些 比 如 它 提 供 了 compareAndSet , 允 许 客 户 端 基 于 AtomicInteger 来实现乐观锁的操作

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java基本数据类型及相互间的转换(转)

    /* 1、如果两个操作数中有一个是double类型,另一个就会转换为double类型; 2、否则,如果有一个操作数是float,另一个就会转化为float; 3...

    会说话的丶猫
  • JVM 学习笔记(二)

    如果还不明白什么是栈帧,可以参考:https://www.jianshu.com/p/b666213cdd8a

    会说话的丶猫
  • springboot引入外部依赖jar包(转)

    会说话的丶猫
  • www3992019com请拨18687679495银河国际零基础快速搭建K歌应用【含源码】

    玩法开天辟地,体验不留缝隙。K歌不遗余力,应用解决效益。总是羡慕别人家的“歌房”苦叹自家“茅草房”消除不了回音和混音?这次就将带你实战K歌功能,细分应用场景,提...

    用户7106032
  • 零基础快速搭建K歌应用【含源码】

    玩法开天辟地,体验不留缝隙。K歌不遗余力,应用解决效益。总是羡慕别人家的“歌房”苦叹自家“茅草房”消除不了回音和混音?这次就将带你实战K歌功能,细分应用场景,提...

    腾讯云大学
  • 这款“狗屁不通”文章生成器火了,效果确实比GPT 2差太远

    话说,BullshitGenerator 这个项目最初起源于知乎上一位网友的提问:“学生会退会申请六千字怎么写?”,本来很简单的一个问题,但是回答中很多跑偏题的...

    AI科技大本营
  • Docker搭建

    进入mysql目录,启动容器 docker run -p 3306:3306 --name docker-mysql -v

    Clive
  • 机器学习(26)之K-Means实战与调优详解

    关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 前言 在K-Means聚类算法原理(...

    昱良
  • 中央网信办网络安全协调局局长赵泽良已任中央网信办总工程师

    据水利部官网6月11日消息,6月4日-5日,2018年水利网信工作会议在京召开,贯彻落实全国网络安全和信息化工作会议精神,安排部署水利网信工作。水利部党组书记、...

    安恒信息
  • 剑指offer——数组中只出现一次的数字

    题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

    AI那点小事

扫码关注云+社区

领取腾讯云代金券