zoukankan      html  css  js  c++  java
  • Java-volatile底层实现原理

    一.volatile

    代码

    package jvm;
    
    public class VolatileVisibilityTest {
    
        private static  boolean initFlag = false;
    //    private static volatile boolean initFlag = false;
        
        public static void main(String[] args) throws InterruptedException {
            new Thread(new Runnable() {
                public void run() {
                    System.out.println("waiting data.....");
                    while(!initFlag) {
                    }
                    System.out.println("success.....");
                }
            }).start();
            
            Thread.sleep(2000);
            
            new Thread(new Runnable() {
                public void run() {
                    prepareData();
                }
    
            }).start();
        }
        
        public static void prepareData() {
            System.out.println("prapareing data......");
            initFlag = true;
            System.out.println("prapareing data end......");
        }
    }

    1.不使用volatile,运行结果:

    waiting data.....
    prapareing data......
    prapareing data end......
    

     2.使用volatile,运行结果:

    waiting data.....
    prapareing data......
    prapareing data end......
    success.....
    

    JMM数据原子操作

    • read(读取):作用于主内存,它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用;

    • load(载入):作用于工作内存,它把read操作的值放入工作内存中的变量副本中;

    • use(使用):作用于工作内存,它把工作内存中的值传递给执行引擎,每当虚拟机遇到一个需要使用这个变量的指令时候,将会执行这个动作;

    • assign(赋值):作用于工作内存,它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作;

    • store(存储):作用于工作内存,它把工作内存中的一个变量传送给主内存中,以备随后的write操作使用;

    • write(写入):作用于主内存,它把store传送值放到主内存中的变量中。

    • lock(锁定):作用于主内存,它把一个变量标记为一条线程独占状态;
    • unlock(解锁):作用于主内存,它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定;

    voliate缓存可见性实现原理:

    底层实现主要是通过汇编lock前缀指令,它会锁定这块区域内的缓存(缓存行锁定)并会回写到主内存。

    IA-32架构开发者对lock指令的解释:

    1)会将当前处理器缓存行的数据立即写会系统主存

    2)这个写回内存的操作会引起在其他cpu里缓存了该内存地址的数据无效(MES协议)

    线程2将initFlag的值store到主内存时要通过总线,cpu总线嗅探机制监听到initFlag值被修改,线程1的initFlag失效,线程1需要重新read initFlag的值。

     二.synchronize

    代码:

    package concurrent;
    
    public class VolatileAtumicTest {
    	private static volatile int num = 0;
    	public static  void increse() {
    //	public static synchronized void increse() {
    		num++;
    	}
    	
    	public static void main(String[] args) throws InterruptedException {
    		Thread[] threads = new Thread[10];
    		for(int i=0; i<threads.length; i++) {
    			threads[i] = new Thread(new Runnable() {
    				public void run() {
    					for(int i=0; i<1000; i++) {
    						increse();
    					}
    				}
    			});
    			threads[i].start();
    		}
    		
    		for(Thread t : threads) {
    			t.join();
    		}
    		
    		System.out.println(num);
    	}
    
    }
    

     不加synchronized,输出:

    num<=10000

    加上synchronized,输出:

    10000

  • 相关阅读:
    转载 jenkins执行selenium 测试 浏览器不显示解决方法
    jmeter用beanshell调用自己写的jar进行MD5加密
    深入理解Spring MVC 思想
    springmvc和json整合配置方法
    getFragmentManager和getChildFragmentManager
    android
    HTTP 请求头与请求体
    Android中ImnageView 中如何让图片拉伸显示?
    ExecutorService 的理解与使用
    SpringMVC源码分析系列
  • 原文地址:https://www.cnblogs.com/hongyedeboke/p/11662548.html
Copyright © 2011-2022 走看看