volatile关键字
作用:轻量级锁,用于多线程的数据共享一致问题,只适用于类变量和成员变量,保证其可见性和有序性。
volatile简单了解
/**
* volatile 关键字简单了解
* 1个线程读数据
* 1个线程改数据
* 查其执行情况如何
*/
public class VolatileFoo {
// 最大值
private final static int MAX = 5;
// 改变的变量
private volatile static int value = 0;
public static void main(String[] args) {
// 读的线程
new Thread(() ->{
//发现本地值和类的变量值不一样时输出信息
int nowValue = value;
while (nowValue < MAX){
if (nowValue != value){
System.out.println("值正在从 "+nowValue+" 改变成 "+value);
nowValue = value;
}
}
},"reader").start();
// 改的线程
new Thread(()->{
int nowValue = value;
while (nowValue < MAX){
System.out.println("value 值自增1 :"+(++nowValue));
value = nowValue;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"update").start();
}
// 没有加 volatile 时输出 读的线程没有监听到改值 也不会停止线程
// value 值自增1 :1
// 值正在从 0 改变成 1
// value 值自增1 :2
// value 值自增1 :3
// value 值自增1 :4
// value 值自增1 :5
// 添加 volatile 时 线程中的值添加可视性和有序性,保证该值在改变时一定会将值刷新到主内存中,并将其他线程的内存缓存失效。
// value 值自增1 :1
//值正在从 0 改变成 1
//value 值自增1 :2
//值正在从 1 改变成 2
//value 值自增1 :3
//值正在从 2 改变成 3
//value 值自增1 :4
//值正在从 3 改变成 4
//value 值自增1 :5
//值正在从 4 改变成 5
}
并发编程三个重要特性和JMM(Java内存模型)
- 并发编程的三个重要特性:原子性,可见性,有序性
- JMM:Java内存模型规定所以的变量存在主内存(RAM)中,而每个线程都有自己的本地内存,线程对变量的所有操作都必须在本地内存进行,而不能直接对主内存进行操作,也访问不到其他线程的本地内存。
- 两者之间的关系
3.1 JMM只保证基础类型读取和赋值的原子性,其他均不保证。要使某些代码片段要有原子性,需要使用synchronized或lock来保证。基础类型要自增也可以使用并发包中的atomic中的类库。
3.2 可见性的保证。在多线程环境中,每个线程第一次读取共享变量时,都是从主内存中获取,再放入本地内存中,后面读取该变量都是从本地内存中取。如果有线程对变量执行更新操作,也是先执行本地内存,再将更新值刷新到主内存中(但是这个刷新到主内存的动作时间不确认,所以可以用volatile来保证更新变量时一定会刷新到主内存,并让其他线程使用该变量一定会从主线程中获取。也可以使用synchronized和lock来保证变量一定会刷新到主内存中)
3.3 JMM可以保证单线程代码执行结果的一致性(不管执行多少次相同代码,其结果是一样的),但是里面的执行顺序不能保证执行每次一样。而在多线程的情况下就要使用volatile,synchronized,lock来保证其有序性。
volatile和synchronized的区别
- 使用上:volatile使用在变量(成员变量和类变量)上,其他的地方不能使用。synchronized使用在方法(普通方法或静态方法)或语句块上,其他地方不能使用。volatile修饰的变量可以为null,而synchronized的语句块中不能为null。
- 对于原子性的保证:volatile不能保证原子性,synchronized是一种排他机制,是不能识别线程的中断标识的所以可以保证原子性。
- 对于可见性的保证:都可以保证,但volatile是用机器指令(lock;)来保证,而synchronized是通过排他方式使同步代码串行化。
- 对于有序性的保证:都可以保证,volatile是通过禁止JVM编译器和处理器进行重排序。synchrnized是通过保证代码块执行结果一样来保证的(不管代码块中的执行顺序)。
- 其他:volatile不会使线程阻塞,synchronized会使线程阻塞。