本篇看一下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技术及健身,获取更多干货。

最新文章

  1. 运行第一个PHP程序
  2. MYSQL、PHP基础、面向对象基础简单复习总结
  3. Java NIO2:缓冲区
  4. 修改msde登录方式,设置sa密码为空
  5. Apache的Order Allow,Deny 详解
  6. heroku空间部署步骤
  7. JavaWeb chapeter 5 Web应用程序状态管理
  8. 存储构造题(Print Check)
  9. mysql 源码编绎修改 FLAGS,调试MYSQL
  10. 关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
  11. trove taskmanger api
  12. 玩转Ecs服务器之搭建Ftp
  13. [JDK8]读写锁的改进:StampedLock
  14. 用winhotkey添加属于自己的快捷键
  15. Could not determine own NN ID in namespace 'mycluster'
  16. 在im4java中使用GraphicsMagick
  17. python 可视化时间转时间元组(自定义)
  18. Codeforces.724G.Xor-matic Number of the Graph(线性基)
  19. Oracle编辑数据时提示:这些查询结果不可更新,请使用ROWI或者SELECT……FOR UPDATE获得可更新结果
  20. 从零搭建SSM框架(二)运行工程

热门文章

  1. 剑指offer数组中重复的数字
  2. nova 云主机 evacuate 简单分析
  3. 通过自定义资源扩展Kubernetes
  4. 牛客网PAT练习场-A+B和C
  5. 开始System.out.println();
  6. CSS3动画之animation-timing-function中的stepshan shu
  7. VUE+ElementUI创建项目
  8. python爬虫-爬取豆瓣电影数据
  9. mysql建数据库的字符集与排序规则说明
  10. CobaltStrike与Metasploit联动配合