zoukankan      html  css  js  c++  java
  • Volatile变量学习

    与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...");
            }
        }
    }
    
    
  • 相关阅读:
    linux里终端安转视频播放器的操作及显示
    String字符串操作
    普通类 抽象类 接口
    java基础
    关于window的端口查看及tomcat的端口修改问题
    eclipse的应用和整理
    mysql学习
    echarts的使用
    Failed to read candidate component class
    oracle学习笔记2
  • 原文地址:https://www.cnblogs.com/Kevin-1992/p/12608437.html
Copyright © 2011-2022 走看看