Atomic是基于unsafe类自旋操作实现的,下面以AtomicInteger类为例进行讲解。

要理解Atomic得先了解CAS

CAS

CAS全程Compare And Swap ,是条并发原语,功能是判断内存中某个值是否与预期值相等,相等就用新值更新旧值,否则不更新。

Java中CAS是基于unsafe类实现的,所有的unsafe类中的方法都是native类修饰的,直接调用操作系统底层资源执行响应的任务。

unsafe.compareAndSwapInt(this, valueOffset, expect, update);

这是一条调用unsafe类中的compareAndSwapInt的方法,this表示当前对象,valueoffset表示当前对象的偏移地址,expect表示预期值

update表示更新值。作用是如果预期值和该对象偏移地址中的值一样,就用更新值更新偏移地址中的值。

AtomicInteger类初始化

// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
} private volatile int value;

上述代码是AtomicInteger类的默认参数初始化过程。其中value就是我们想要进行操作的那个值。加上volatile是为了

保证修改该值后立马被其他线程感知到。

刚开始实例化unsafe类,这没什么好说的,因为AtomicInteger类中方法都是通过unsafe类中方法来操作的。在静态代码块中通过

unsafe.objectFieldOffset方法获取value值的偏移量。也可以说是引用地址,以后通过该地址就可以随时获取value值和更改value值

AtomicInteger中方法的执行流程

这里我们以常用的getAndIncrement方法为例

/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}

可以看到,该方法是调用unsafe类中的getAndAddInt方法,继续跟踪该方法,进入unsafe类源代码中

可以看到,调用unsafe类中getIntVolatile方法,方法参数var1为传入的对象,即上述的AtomicInteger类的对象

var2为偏移地址,该方法的作用是通过该对象的偏移地址找到值,也就是找到上文的value值。(注意!这里已经

不是在AtomicInteger类源代码中了而是进入了Unsafe类源代码中,所以这里的this.getIntVolatile是unsafe类中的

getIntVolatile方法,该方法不是在AtomicInteger类中!)获取到目前的value值后调用compareAndSwapInt方法,

使用获取到的value值和当前当前对象地址偏移量中的值进行比较,如果相同就更新值,并且退出循环,否则就继续

进入循环获取该偏移地址中的最新值。为什么这里会导致使用var5 = getIntVolatile获取偏移地址中的值后后面compareAndSwapInt

方法var5又会出现不等于偏移量地址上的值呢?按道理来说两次获取同一个偏移地址上的值是肯定会相同的,但是这里我们

考虑多线程的情况下,当两个线程同时获取当前偏移地址上的值,由于compareAndSwapInt是原子操作,所以必定有一个

线程会先执行完,并且改掉内存偏移地址上的值,那么另一个线程就会出现两次获取内存偏移地址上的值却不一致的情况,

出现这种情况就需要重新获取该值并且在此执行compareAndSwapInt,直到成功为止。

CAS与synchronized比较

CAS支持多个线程并发修改。并发程度高

synchronized一次只有一个线程修改,并发程度较低

CAS只支持一个共享变量的原子操作

synchronized可以对个变量进行加锁

CAS会出现ABA问题

深入理解Atomic原子类的更多相关文章

  1. Java CAS同步机制 原理详解(为什么并发环境下的COUNT自增操作不安全): Atomic原子类底层用的不是传统意义的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的安全性。

    精彩理解:  https://www.jianshu.com/p/21be831e851e ;  https://blog.csdn.net/heyutao007/article/details/19 ...

  2. JUC 中的 Atomic 原子类总结

    1 Atomic 原子类介绍 Atomic 翻译成中文是原子的意思.在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的.在我们这里 Atomic 是指一个操作是不可中断的.即使是 ...

  3. Juc中Atomic原子类总结

    1 Atomic原子类介绍 2 基本类型原子类 3 数组类型原子类 4 引用类型原子类 5 对象的属性修改类型原子类

  4. (转)Java atomic原子类的使用方法和原理(一)

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  5. Atomic原子类

    Atomic原子类 Atomic原子类位于并发包java.util.concurrent下的java.util.concurrent.Atomic中. 1. 原子更新基本类型类 使用原子方式更新基本数 ...

  6. Java线程--Atomic原子类使用

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11871241.html Java线程--Atomic原子类使用 package concurr ...

  7. [Java多线程]-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  8. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  9. J.U.C 系列之Atomic原子类

    一 什么是原子类? 所谓原子类必然是具有原子性的类,原子性操作--原子操作,百度百科中给的定义如下 "原子操作(atomic operation)是不需要synchronized" ...

随机推荐

  1. graph-Dijkstra's shortest-path alogorithm

    直接贴代码吧,简明易懂. 后面自己写了测试,输入数据为: a b c d e 0 1 4 0 2 2 1 2 3 1 3 2 1 4 3 2 1 1 2 3 4 2 4 5 4 3 1 也就是课本上1 ...

  2. UVALive - 3942 Remember the Word (Trie + DP)

    题意: 给定一篇长度为L的小写字母文章, 然后给定n个字母, 问有多少种方法用这些字母组成文章. 思路: 用dp[i]来表达[i , L]的方法数, 那么dp[i] 就可以从dp[len(x) + i ...

  3. x mod a=r(N对a,r)

    //模数不一定互质,互质才可以用孙子定理. /* https://blog.csdn.net/zmh964685331/article/details/50527894 uu遇到了一个小问题,可是他不 ...

  4. 【转】git bash here 右键菜单失效后的修复方法

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\git_shell] @="Git Ba&sh Here"   [ ...

  5. Makefile基础(三)

    第一章:C语言之Makefile基础(一) 第二章:C语言之Makefile基础(二) 再来看一个简单的例子: [root@localhost linux_c]# cat Makefile foo = ...

  6. 00018_流程控制语句switch

    1.选择结构switch switch 条件语句也是一种很常用的选择语句,它和if条件语句不同,它只能针对某个表达式的值作出判断,从而决定程序执行哪一段代码. 2.switch语句的语法格式 swit ...

  7. 聊聊、Nginx 初始化日志文件

    我们接着上一篇文章继续来看看 ngx_regex_init()函数.搜索 ngx_regex_init 得到位置为src/core/ngx_regex.c:ngx_regex_init(void). ...

  8. Django模板导入和替换、以及对数据库的增加、查看

    静态文件引入的3中方式:例如对html模板里面对css样式的引入 STATIC_URL = '/static666/'STATICFILES_DIR=[ os.path.join(BASE_DIR,' ...

  9. Python IO多路复用select模块

    多路复用的分析实例:服务端.客户端 #服务端配置 from socket import * import time import select server = socket(AF_INET, SOC ...

  10. [git 学习篇] 修改文件

    http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013743858312764d ...