生活
天气贼好的一个礼拜二。
生活就是生下来活下去。
简述
volatile是JAVA中的一个关键字,在JDK1.5以前据说饱受争议,在程序中使用经常出现一些出入意料的结果。
这个么,从volatile的翻译就能看出来,就是不稳定的意思嘛。
JDK1.5以后,volatile才重获生机。(我认为是Doug Lea写的并发包把它发扬光大了)。
学习它有什么用?
1、有助于内存模型的深入了解
2、有助于并发编程的深入学习
3、方便后期与synchronized关键字对比学习
特性
1、可见性
2、有序性(一定程序上保障有序性)
注意 没有原子性,所以单纯使用这个关键字,并不是线程安全的。需要搭配其他锁来保证线程安全。
使用
直接套用前面的场景
场景说明:
两个线程共享一个变量stop.
A线程,当stop为false,则一直运行;为true则停止。
B线程,设置stop为true
public class Test {
static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程A运行中");
while (!stop);
System.out.println("线程A已停止");
}
}).start();
Thread.sleep(10);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程B运行中");
stop = true;
System.out.println("stop设置为true,线程B已停止");
}
}).start();
}
}
其中一次运行结果:
线程A运行中
线程B运行中
stop设置为true,线程B已停止
由此见得,一个普通的变量在多线程环境下不具有可见性。
只需要给stop变量加上关键字volatile,在多线程环境下就不会在出现不可见的情况。
PS:上面讲到volatile实现可见性,其实我认为这个可见性本身就是基于 一定程度的有序性实现的。即对volatile的变量读取之前,必须保证前面的更新已经刷入主内存。
这是通过内存屏障来禁止重排序实现了一定的有序性,从而达到可见性。
实现原理
关于volatile的实现原理,我看了很多博客,讲的很多,都是对的,但是讲的实在太多了,本来想把他们讲的东西抄下来,感觉意义不大。自己简单的分析一下:
1、为什么会出现不可见性的问题?
原因在于:多线程环境下存在工作内存和主内存,每个线程的工作内存都是独立的,在使用一个变量之前要先拷贝一份副本到自己的工作内存,更新一个变量,需要先在自己的工作内存中更新,在刷入到主内存。
不可见性出现的问题就在于A线程读取变量的时候,可能B线程更新了但是并没有刷入主内存。导致不一致的情况。
2、如果避免不可见性?
从现实角度分析,就必须强制要求在A线程读取变量之前其他线程的更新操作必须刷入主内存。也就是volatile的关键字语义,被volatile修饰的变量,被一个线程修改后可以及时被其他线程读取到。
3、如果实现2中提到的避免不可见性的操作。
两种办法:
3.1互斥锁:即多个线程访问使用同一个变量时,同一个时刻只由一个线程上锁操作访问这个变量,访问结束unlock()后其他线程才可以访问,强制实现了可见和有序。
3.2volatile:他的实现原理就是jvm内存模型中本身的内存屏障,在volatile写的后面加上store load 屏障,禁止volatile写与后面的操作重排序,即volatile写必须先于后面的操作。
总结反思
这是我理解的volatile,有不对和不恰当的烦请指正!