Volatile是java虚拟机提供的轻量级同步机制。三大特性
- 保证可见性
package com.kuang.tvolatile;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
// 不加 volatile 程序就会死循环! // 加 volatile 可以保证可见性
private volatile static int num = 0;
public static void main(String[] args) { /
new Thread(()->{
// 线程 1 对主内存的变化不知道的
while (num==0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num);
}
}
- 不保证原子性。使用原子类,可解决原子性问题.unsafe
- 禁止指令重排。 什么是指令重排:你写的程序,计算机并不是你写的那样去执行的。 源代码-->编译器优化重排-->指令并行也可以能会重排-->内存系统也会重排-->执行 处理器在进行指令重排的时候,考虑:数据之间的依赖性
JMM
JAVA内存模型。不存在的东西,完全是个概念约定
关于JMM一些同步的约定
- 线程解锁前:必须把共享变量立刻刷回主存
- 线程加锁前:必须读取主存中的最新值到工作内存中
- 加锁跟解锁是同一把锁 线程:工作内存 主内存
八种操作
lock(锁定) unlock(解锁) read(读取) load(载入) use(使用) assign(复制) store(存储) write(写入) 对称使用
CAS
比较当前工作内存中的值和主内存中的值,如果这个值是期望的则执行操作,否则一直循环 缺点:由于底层是自旋锁会浪费时间。一次性只能共保证一个共享变量的原子性。会存在ABA问题
ABA问题
当一个线程被另一个线程修改了CAS。就会产生ABA问题。 解决ABA原子引用:带版本号的原子操作。
公平锁:不能插队的锁。 非公平锁:可以插队的锁。(默认都是非公平锁) 可重入锁:递归锁。拿到了外面锁也就可以拿到里面的锁。自动获得 自旋锁:不断的去尝试,直到成功为止。spinLock