本篇看一下Volatile关键字和原子引用。

上图就是JUC包结构,总共分成三块

(1)java.util.concurrent:并发包基础类,包括阻塞队列,线程池相关类,线程安全Map等。

(2)java.util.concurrent.atomic:原子引用相关类

(3)java.util.concurrent.locks:线程锁相关类

线程池技术在之前的讲解应该很清楚了,今天主要解析一个volatile关键字以及原子引用的相关类。这一篇文件涉及到JMM(java内存模型)的知识,之前也有讲解。

一、volatile

这个关键字,是JVM提供的轻量级的同步机制。可能在业务功能开发中很少涉及,但其是JUC包里面拥有重要地位的大哥。

首先看下理论:

(1)保证变量内存可见性:就是当前线程对某个volatile修饰的变量进行操作的话会及时通知到其它线程。比如现在的在线编辑文档,当某个人编辑了文档并保存之后,其他人会立马收到文档已被修改的通知。

(2)不保证原子性: 原子性的意思就是某个元素已经是最小的了,不可在被分割,比如现实中原子就是最小的粒子了,不可能再被分割。而映射到这边就是说某个操作不可在被分割成两个或多个操作,要么成功,要么失败。

(3)禁止指令重排:JVM为了获取最快的运行速度,会在底层一些没有先后性要求的指令进行一些指令重排的操作,在代码层面是一步一步执行,但在底层执行的时候并不是如此。比如JVM创建了一个对象有三步,创建实例对象、分配空间、将引用指向内存空间,但是第一步和第二步并没有什么关系,这个时候就可能会发生指令重排的操作。

代码示例:

(1)可见性代码验证:

当资源类变量a未加volatile关键字修饰的时候

当添加了volatile关键字修饰后:

(2)不保证原子性验证:

如果保证原子性,那么最后输出的结果应该是20000,而真实输出是19734,所以这可以 证明其不保证原子性。

JVM为了提供了可保证原子性的原子类。

二、原子类

下图就是原子类的结构图

先用AtomicInteger类是否可以保证原子性。不多说,上图片。

可以看到,用原子类AtomicInteger类是可以获取期望值的,也就是保证了原子性。

接下来看一下原子类底层是怎么样的。

上图可以看到,有三个变量,分别是value,valueOffset,unsafe。

(1)value:是volatile关键字修饰的,也就是说原子类底层也是volatile变量。

(2)valueOffset:当前变量的内存位移值。

(3)unsafe:下图可以看到,unsafe类里面都是native修饰的本地方法,是直接调用其他语言进行操作变量的。

看一下原子类的addAndGet方法为什么能实现原子性呢?

点进去会看到它调用了unsafe的getAndAddInt方法。

继续点下去会看到如下方法,里面有个compareAndSwap。

介绍一个compareAndSwap方法,简称CAS(比较并交换),其有三个值,内存值V,旧的预估值A,更新值B。只有当V和A相等的时候,才会将变量的的值修改为B,否则什么都不干。

可以看到,上述的getAndAddInt方法是个自旋锁的实现,一直调用getIntVolatile(也是本地方法)方法获取对象的最新值,获取之后就会调用CAS方法。

CAS:原称为Compare-And-Swap,比较并交换,是一条cpu的并发原语,它的功能是判断内存某个位置的值是否为预期值,如果是则更改为预期值,这个过程是原子的。

并发原语体现在调用unsafe的方法。原语是属于操作系统的范畴,原语的执行必须是联系的,也就是原子性,不会造成所谓的数据不一致的问题。(这个我也不是很懂,毕竟我不是科班出身的程序员,应该是要学操作系统才会明白)

(如果大厂面试的时候让你手写一个自旋锁,就把上述代码糊他脸上)

上述就是其保证原子性的方法,利用自旋锁和unsafe类。

说完原子类的底层,进行拓展一下:上述可以看到,原子类java只提供了基本类型的封装,例如AtomicInteger,AtomicLong等,但是工作中需要很多其他自定义的实体,也要保证原子性,该怎么办呢?

别慌,JVM还提供了原子引用类型AtomicReference,下图可见此类是一个泛型类。

下次会带大家看一下CAS导致的ABA问题。

=======================================================

我是Liusy,一个喜欢健身的程序员。

欢迎关注公众号【Liusy01】,一起交流Java技术及健身,获取更多干货。

详解volatile关键字和原子引用的更多相关文章

  1. 详解 volatile关键字 与 CAS算法

    (请观看本人博文 -- <详解 多线程>) 目录 内存可见性问题 volatile关键字 CAS算法: 扩展 -- 乐观锁 与 悲观锁: 悲观锁: 乐观锁: 在讲解本篇博文的知识点之前,本 ...

  2. 详解volatile 关键字与内存可见性

    先来看一个例子: public class VolatileTest {            public static void main(String[] args) {           T ...

  3. Java之static静态关键字详解|final关键字详解

    前言 在Java语言中,static表示"静态"的意思,使用场景可以用来修饰成员变量和成员方法,当然也可以是静态代码块.static的主要作用在于创建独立于具体对象的域变量或者方法 ...

  4. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part5:右值引用就是右值吗?

    本文为第五部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  5. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part3:右值引用

    本文为第三部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/4220233.html. 右值引用 如果x是任意类型,那么x&&则被称作一个 ...

  6. 详解JNDI的lookup资源引用java:/comp/env

    ENC的概念:     The application component environment is referred to as the ENC, the enterprise naming c ...

  7. 详解JNDI的lookup资源引用 java:/comp/env

    ENC的概念:     The application component environment is referred to as the ENC, the enterprise naming c ...

  8. 详解php中函数的引用传递和返回 (附代码)

    本篇文章带大家了解一下php的引用,详细介绍一下函数的引用传递和引用返回.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助.php的引用(就是在变量或者函数.对象等前面加上&符号 ...

  9. Java(2)详解注释&关键字&常量&变量&标识符

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201497.html 博客主页:https://www.cnblogs.com/testero ...

随机推荐

  1. hdfs常用api(java)

    1.下载文件到本地 public class HdfsUrlTest { static{ //注册url 让java程序识别hdfs的url URL.setURLStreamHandlerFactor ...

  2. 关于Java的对象,锁和对象的内存布局、访问定位

    1. 对象的创建和分配 创建对象(如克隆.反序列化)通常仅仅一个new关键字,但在虚拟机中,对象的创建的过程需要如下步骤: 类加载检查 先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并 ...

  3. 通俗易懂的 Java 位操作运算讲解

    所有数值都是2进制 软件开发者都知道 10 进制.16 进制.8 进制. 比如数字 10 的各位进制形式表现如下. 十进制:10 八进制:012 十六进制:0x0a 二进制:1010 原码 反码 补码 ...

  4. Java中抽象类和接口的介绍及二者间的区别

    接口(Interface)和抽象类(Abstract Class)是支持抽象类定义的两种机制. 一.抽象类 在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称 ...

  5. Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践

    Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 目录 Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 引子 FeignClient的 ...

  6. Oracle - Flashback standby after resetlogs on primary

    一.概述 本文将给大家介绍主库使用rman做不完全恢复后,备库如何通过flashback,继续同步 二.正式实验 本次实验采用的是oracle 11g 单实例 + oracle 11g 单实例dg 1 ...

  7. 医疗seo常用的图标工具

    http://www.wocaoseo.com/thread-304-1-1.html 下面是一些医疗seo常用的一些图表工具,这些都是些最简单的工具,主要放置这里以防止以后有作用. 1,医疗的常用搜 ...

  8. 【原创】Linux虚拟化KVM-Qemu分析(二)之ARMv8虚拟化

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...

  9. 解决git add README.md 时报错 fatal: pathspec 'README.md' did not match any files

    解决办法一: 直接在远程仓库创建然后在本地$ git pull origin master 解决办法二: 换成$ touch README.md在本地创建修改后再commit push上去

  10. vue前端获取env中的常量

    process.env.常量名   如:process.env.MIX_APP_URL