J(java)U(util)C(concurrent)其实就是指上图的三个包。

1、Volatitle

jvm提供的轻量级同步机制,它有三个特征

  • 保证可见性

  • 禁止指令重排

  • 不保证原子性

    JMM(Java Memory Model)

    java内存模型,一个非实际存在的抽象概念,是一个组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。

    JMM关于同步的规定
    • 加锁前,线程从主存中读取最新的值到工作内存

    • 解锁前,线程将自己的工作内存中的共享变量值写入主存内

    • 加锁解锁,是对同一把锁

      JVM运行程序的实体是线程,每个线程进行创建是,JVM都会为其创建该线程独有的工作内存(栈空间)。当线程操作内存中的变量时,需要先将其拷贝到自己的空间,整一个副本,然后在自己的工作内存中对其操作,之后,将副本写回主内存

      从上述的描述,可以看到:在多线程并发的情况下,由于存在副本和副本写回这样的步骤,势必会出现类似脏读、幻读、不可重复读的问题。

    比如:线程1、线程2将数据进行拷贝到自己的工作内存后,线程1进行数据修改并写回主内存,但是线程2还是使用原来的数据

    所以,只要有一个线程写回主存,那么应该通知其他线程,告诉它们:你们持有的此变量副本数据已经过期,赶紧从主内存读取,更新一下,别用旧的数据啦~~~
    这种效果:即所谓的可见性

2、指令重排

​ 计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令进行重排序

单线程环境下,确保程序最终执行结果和代码顺序执行的结果一致
处理器在进行重排序时必须要考虑 指令之间的数据依赖性
多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性无法确定,结果无法预测.

volatile实现禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象

2.1 内存屏障(Memory Barrier)

内存屏障又称内存栅栏,是一个CPU指令,它的作用有两个

  • 保证特定操作的执行顺序
  • 保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)

由于编译器和处理器都能执行指令重排优化,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。内存屏障另一个作用是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读取到这些数据的最新版本。