zoukankan      html  css  js  c++  java
  • 多线程中对static和volatile的理解

    问题来源于编码规范的一个例子


    一. 关于server模式下的主存和工作内存  
    规则40     多线程访问同一个可变变量,需增加同步机制
    说明:根据Java Language Specification中对Java内存模型的定义, JVM中存在一个主内存(Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。每个线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。根据上述内存模型的定义,要在多个线程间安全的同步共享数据就必须使用锁机制,将某线程中更新的数据从其工作内存中刷新至主内存,并确保其他线程从主内存获取此数据更新后的值再使用。
    示例:
         不好:下面的代码中,没有对可变数据stopRequested的访问做同步。程序期望在一秒钟后线程能停止。但在用java 1.6的server模式运行此程序(Java –server StopThread)时,程序陷入死循环,不能结束。
    public class StopThread 
    {
        private static boolean stopRequested;
    
        public static void main(String[] args) throws InterruptedException 
    {
            Thread backgroundThread = new Thread(new Runnable() 
    {
                public void run() 
    {
                    int i = 0;
                    while (!stopRequested)
    {
                        i++;
                         }
                }
            });
    
            backgroundThread.start();
    
            TimeUnit.SECONDS.sleep(1);
            stopRequested = true;
        }
    }
         
     
    这里为什么会陷入死循环,永远不会停止呢?
    参考两篇文章
    http://m.blog.csdn.net/blog/lyy5682077/17588155
    http://www.cnblogs.com/trytocatch/archive/2013/01/07/2850002.html
    JIT或HotSpot编译器在server模式和client模式编译不同,server模式为了使线程运行更快,如果其中一个线程更改了变量boolean flag 的值,那么另外一个线程会看不到,因为另外一个线程为了使得运行更快所以从寄存器或者本地cache中取值,而不是从内存中取值,那么使用volatile后,就告诉不论是什么线程,被volatile修饰的变量都要从内存中取值。《内存栅栏》
     
    java在server模式下,各个线程使用各自的工作内存,一个线程改变了变量的值,另外一个线程并不会从主存中取
     
    上面例子中的问题,变量stopRequested前加上volatile可以解决:
    增加了 synchronized同步机制后,程序就能正确地在 1秒后终止。另一个方案是在变量前增加     volatile 关键字。
    public class StopThread 
    {
        private static boolean stopRequested;
        
        private static synchronized void requestStop() 
    {
            stopRequested = true;
        }
        
        private static synchronized boolean isStopRequested() 
    {
            return stopRequested;
        }
    
        public static void main(String[] args) throws InterruptedException 
    {
            Thread backgroundThread = new Thread(new Runnable() 
    {
                public void run() 
    {
                    int i = 0;
                    while (!isStopRequested()) 
    {
                        i++;
                         }
                }
            });
    
            backgroundThread.start();
    
            TimeUnit.SECONDS.sleep(1);
            requestStop();
        }
    }
     
    二. static和volatile的区别
    参考http://blog.sina.com.cn/s/blog_4e1e357d0101i486.html
    1. volatile是告诉编译器,每次取这个变量的值都需要从主存中取,而不是用自己线程工作内存中的缓存.
    2. static 是说这个变量,在主存中所有此类的实例用的是同一份,各个线程创建时需要从主存同一个位置拷贝到自己工作内存中去(而不是拷贝此类不同实例中的这个变量的值),也就是说只能保证线程创建时,变量的值是相同来源的,运行时还是使用各自工作内存中的值,依然会有不同步的问题.
  • 相关阅读:
    atitit.TokenService v3 qb1 token服务模块的设计 新特性.docx
    Atitit attilax在自然语言处理领域的成果
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结
    atitit。企业的价值观 员工第一 vs 客户第一.docx
    Atitit 实现java的linq 以及与stream api的比较
    Atitit dsl exer v3 qb3 新特性
    Atititi tesseract使用总结
    Atitit 修改密码的功能流程设计 attilax总结
    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx
  • 原文地址:https://www.cnblogs.com/cvbaka/p/4764503.html
Copyright © 2011-2022 走看看