与Synchronized关键字区别:
2020-3-25 这两个比较某种程度上并不是一个层面,volatile不具有原子性,只是读写前后加入屏障进行的可见性保障。
synchronized是JVM对程序的加锁机制,会使执行线程阻塞;
volatile变量则不会,所以说是相对于synchronized而言更轻量的同步机制。
作用
1.volatile修饰的变量可以保证更新操作对其它线程可见;
2.当被它修饰后,编译器与运行时都会注意到这个变量是共享的,所以不会将该变量上的操作和其他内存操作一起重排序。
禁止指令重排序是第二个语义
注意:
/**
* 类描述:volatile保证变量更新可见性,但是不保证是原子性,所以使用的时候仍然需要注意线程安全。
* @author: Wanggd
* 时间:2017年5月29日
*/
public class VolatileTest {
public static volatile int race = 0;
public static void increase(){
//++计算并不是原子的。要想保证线程安全,依然需要借助synchronized或者lock。
race ++;
}
private static final int THREADS_COUNT = 20;
public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_COUNT];
for(int i=0;i<threads.length;i++){
threads[i] = new Thread(new Runnable() {
public void run() {
for(int i=0;i<10000;i++){
increase();
}
}
});
threads[i].start();
}
while(Thread.activeCount() > 1){
Thread.yield();
}
System.out.println(race);
//期望结果为200000
//实际结果往往小于200000; 193582 问题出在++操作。
}
}
另一个volatile的案例就是单例模式:
http://blog.csdn.net/kevin_king1992/article/details/72801015
2020-3-25 最近又学习了一下这个知识点,并且分享下面一个简单的示例,大家可以运行下看看,很多框架中常见到类似的案例。
import java.util.Random;
/**
* 应用volatile可见性的例子,常用于判断性的场景。
* 下面是一个模拟容器启动失败后再度调用的例子。
*/
public class VolatileDemo {
public static void main(String[] args) {
SpringContainer springContainer = new SpringContainer();
new Thread(new SpringRunTask(springContainer)).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--启动监控Spring容器是否初始化完成,否则继续初始化--");
while (!springContainer.successInit) {
System.out.println("-- 再重新初始化一次,否则将记录错误 --");
springContainer.init();
}
System.out.println("--Spring容器初始化完成,初始化完成关闭当前线程--");
}
static class SpringRunTask implements Runnable{
private SpringContainer springContainer;
SpringRunTask (SpringContainer springContainer) {
this.springContainer = springContainer;
}
@Override
public void run() {
springContainer.init();
}
}
static class SpringContainer {
public volatile boolean successInit = false;
public void init() {
System.out.println("Spring Application Context Init....");
try {
Thread.sleep(300);
/**
* 设置1/3的概率失败
*/
int r = new Random().nextInt(3);
if (r == 1) {
throw new RuntimeException("初始化异常....");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
successInit = true;
System.out.println("Completed...");
}
}
}