1. JMM
问题:请你谈谈你对volatile的理解?
volitile 是 Java 虚拟机提供的一种轻量级的同步机制 ,三大特性:
- 保证可见性
- 不保证原子性
- 禁止指令重排
线程之间如何通信?
- 通信是指线程之间以如何来交换信息。
- 一般线程之间的通信机制有两种:共享内存和消息传递。
- Java的并发采用的是共享内存模型~
什么是JMM?
- Java内存模型即JMM(Java Memeory Model),它并不是真实存在的,而是Java中抽象出来的一个概念,用于多线程场景。
共享内存模型 指的就是 Java内存模型 ( 简称 JMM) { Java多线程内存模型 }- JMM 本身是一种抽象的概念,并不真实存在,它描述的是一组规则或者规范~
- JMM描述了一组规则或规范,定义了一个线程对共享变量写入时对另一个线程是可见的,从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系
- 关于JMM的一些同步的约定:
- 线程解锁前,必须把共享变量立刻刷回主存。
- 线程加锁前,必须读取主存中的最新值到工作内存中!
- 加锁和解锁必须是同一把锁
- 在JMM中把多个线程间通信的共享内存称之为主内存{Main Memory},线程之间的共享变量存储在主内存(main memory)中,而在并发编程中每个线程都维护自己的一个本地内存{工作内存},每个线程都有一个私有的本地内存(Local Memory),其中保存的数据是从主内存中拷贝过来的数据副本,而JMM主要是控制本地内存和主内存之间的数据交互;
本地内存是 JMM 的一个抽象概念,并不真实存在。从上图来看,线程A与线程B之间如要通信的话,必须要经历下面2个步骤:
- 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
- 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。
下面通过示意图来说明线程之间的通信:
总结:
- 什么是Java内存模型:Java内存模型简称JMM,定义了一个线程对另一个线程可见。
- 共享变量存放在主内存中,每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。
怎样保证线程B可以同步感知线程A修改了共享变量呢?
- 使用volatile关键字修饰变量
- 使用synchronized修饰修改变量的方法
- wait/notify
- while轮询
JMM内存模型底层八大原子操作:
2. Volatile
volitile 是 Java 虚拟机提供的一种轻量级的同步机制 ,三大特性:
- 保证可见性
- 不保证原子性
- 禁止指令重排
使用volatile可以保证线程间共享变量的可见性,详细的说就是符合以下两个规则:
- 线程对共享变量进行修改之后,要立刻回写到主内存。
- 线程对共享变量读取的时候,要从主内存中读,而不是缓存。
- 对于可见性,Java提供了volatile关键字来保证多线程共享变量可见性和禁止JVM指令重排,volatile提供happens-before{先行发生}的保证,volatile变量可以确保先行关系,即写操作会发生在后续的读操作之前,确保一个线程的修改能对其它线程是可见的。当一个共享变量被volatile关键字修饰时,它会保证修改的值会立即被更新到主内存中,当有其它线程需要读取时,它会从主内存中读取最新的值。
- {volatile关键字为变量的访问提供了一种免锁机制}
- 但是,volatile并不能保证原子性,例如用volatile修饰count变量,那么count++操作就不是原子性的{因为首先count++本身就不是原子性操作}
- 而java.util.concurrent.atomic包下的原子类提供的atomic方法可以保证对其进行原子性操作,比如AtomicInteger类提供的getAndIncrement()方法会原子性的进行增量操作把当前值加1。
synchronized 和 volatile 的区别是什么?
- synchronized 表示同一时间只有一个线程可以获取作用对象的锁,去进入同步代码块或者同步方法来执行代码,其他线程会被阻塞。
- volatile 表示变量在 CPU 的寄存器中是不确定的,必须从主存中读取。保证多线程环境下变量的 可见性;禁止指令重排序。
区别:
- volatile 是变量修饰符,volatile关键字只能用于变量;synchronized 关键字可以修饰方法以及代码块。
- volatile 仅能实现变量的修改可见性,不能保证原子性;而 synchronized 则可以保证对变量的修改操作的可见性和原子性{加锁和解锁}。
- volatile 不会造成线程的阻塞;synchronized 会造成其它线程的阻塞。
- volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。