一、引言
今天跟小编一起学习下Java轻量级的同步机制锁Volatile~
二、目录
五、Volatile 和 synchronized 区别 ?
三、什么是 Volatile ?
Volatile 是Java虚拟机提供 “轻量级的同步机制”
Volatile 三大特性:
- 1、保证的可见性
- 2、不保证原子性
- 3、禁止指令重排
四、Volatile 特性
4.1 可见性
可见性:创建两条线程,共享同一个变量,一条线程更新了变量,会及时刷新回主内存。以保证其他线程能立即得知变量的最新值。
/**
* @Author WangYan
* @Date 2023/3/13 15:11
* @Version 1.0
* 测试 Volatile 可见性
* 可见性: 创建两条线程,共享同一个变量,一条线程更新了变量,会及时刷新回主内存。以保证其他线程能立即得知变量的最新值。
* 注意: System.out.println(); 底层方法被 synchronized 锁修饰,会保证可见性
*/
public class Test01 {
private volatile static int num = 1;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (num == 1){
}
}).start();
TimeUnit.SECONDS.sleep(1);
num = 0;
}
}
4.2 原子性
原子性: 要么全部成功,要么全部失败!
/**
* @Author WangYan
* @Date 2023/3/13 16:20
* @Version 1.0
* 测试 Volatile 原子性
* 原子性: 要么全部成功,要么全部失败!
*/
public class Test02 {
private volatile static int num = 0;
public static void main(String[] args) throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 1000; i++) {
// 模拟多条线程执行 num++,以测试原子性
num++;
}
};
List<Thread> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Thread thread = new Thread(runnable);
thread.start();
list.add(thread);
}
for (Thread thread : list) {
// 线程值进行累加
thread.join();
}
System.out.println(num);
}
}
运行结果:
正确结果应该是 50000,输出的是49934。明显是有问题,可以证实:Volatile 不保证原子性
4.3 禁止指令重排
JMM要求有序性
计算机在执行程序时,为了提高性能,编译器和处理器常常会做指令重排,一把分为以下3种
单线程: 环境里面确保程序最终执行结果和代码顺序执行的结果一致.(单线程不用关心指令重排)
处理器在进行重新排序是必须要考虑指令之间的数据依赖性
多线程: 环境中线程交替执行,由于编译器优化重排的存在,两个线程使用的变量能否保持一致性是无法确定的,结果无法预测
源码写的顺序不见得和编译的指令顺序一样
例子:
public void mySort(){
int x=11;//语句1
int y=12;//语句2
x=x+5;//语句3
y=x*x;//语句4
}
编译后的可能为顺序:
1234
2134
1324
问题:
请问语句4 可以重排后变成第一条码?
答:因为存在数据的依赖性 ,所以语句4 没办法排到第一个
五、Volatile 和 synchronized 区别 ?
- 1、Volatile 保证可见性,但是不保证原子性
- 2、性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized。
但是要注意voliate关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。
六、拓展
使用JUC原子类包,保证原子性操作,效率比Lock和Sync 锁更高!
代码:
/**
* @Author WangYan
* @Date 2023/3/13 17:03
* @Version 1.0
* 测试 保证原子性
* 使用JUC原子类包,保证原子性操作,效率比Lock和Sync 锁更高!
*/
public class Test02Atom {
private static AtomicInteger num = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 1000; i++) {
// 模拟多条线程执行 num++,以测试原子性
num.incrementAndGet(); // 底层是 sun.misc 包,CAS
}
};
List<Thread> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Thread thread = new Thread(runnable);
thread.start();
list.add(thread);
}
for (Thread thread : list) {
// 线程值进行累加
thread.join();
}
System.out.println(num);
}
}
运行结果:
输出结果50000.可以证实:保证原子性
七、总结
拜拜~
有任何问题欢迎大家指出~
Thank You !