一、Volatile关键字的理解
volatile时java虚拟机提供的轻量级同步机制
1.1 保证可见性
轻量级volatile会及时通知各个线程主内存中变量的变化
1.2 不保证原子性
某个线程做某个具体业务时候,中间不可以被加塞或者被分割,需要完整的完成,可以与实务类比。
num++ 在多线程情况下是非线程安全的,去和不加synchronized来解决呢?
- 太重量不建议用
1.3 禁止指令重排
避免多线程环境下出现乱序执行的现象
1.4 你在哪里使用过volatile?
单例模式:
二、JMM内存模型
它是一种抽象的概念,并不存在,他描述的是一种规范和约束规定。通过这组规定定义了程序中各个变量的访问方式。
主内存是共享内存区域,所有的县城都可以访问,线程使用必须拷贝到自己的内存空间,操作完成后再写会主内存。
线程之间无法访问对方的工作内存。
JMM规定:
线程解锁前,必须把共享变量的值刷新回主内存
线程加锁前,必须读取主内存的最新值到自己的工作内存
枷锁和解锁是通一把锁
三、CAS
3.1 概念
CAS比较与交换CompareAndSet(),是CPU并发原语。
原语:连续,不允许中断,原子指令,不会造成线程不安全。
真实值与期望值相同 true 修改成功
也就是比较主内存与工作内存中的值。
Unsafe类是CAS的核心类,由于Java无法直接访问底层,需要通过native方法来访问,基于该类可以直接操作特定内存的数据。
如果使用Synchronized 在同一时间段只有一个线程使用,降低了高并发性。
如果使用CAS比较,一致性,并发性都得到了保证。
3.2 CAS缺点
没有枷锁,虽然保证了一致性,提高了并发,但是需要多次比较。
循环时间长do while(),如果CAS失败,自旋,长时间不成功,给CPU带来很大的开销。
只能保证一个共享变量的原子性
ABA问题 *****很重要!!!
3.3 原子类AtomicInteger的ABA问题谈谈?
【狸猫换太子】
比如右侧的线程时间比较快,从主内存中copy了A,然后改回B再写回主内存为B,10S的时候,左侧的线程比较主内存,结果没有变化,觉得并没有动,操作成功,过程是有问题的,主内存中的数据已经被右侧的线程修改了!
如何解决ABA问题?
+ 1.原子引用来解决
+ 2.修改版本号【类似时间戳】
演示ABA问题
版本号时间戳解决问题: