`
lhgyy00
  • 浏览: 144412 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

java的volatile关键字小记

阅读更多
     用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)



=========================分割线1=================================
在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。



一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。以下例子展现了volatile的作用:


public class StoppableTask extends Thread {

  private volatile boolean pleaseStop;


  public void run() {

    while (!pleaseStop) {

     // do some stuff...

    }

 }


  public void tellMeToStop() {

   pleaseStop = true;

  }

} 


假如pleaseStop没有被声明为volatile,线程执行run的时候检查的是自己的副本,就不能及时得知其他线程已经调用tellMeToStop()修改了pleaseStop的值。



Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。如果配合Java 5增加的atomic wrapper classes,对它们的increase之类的操作就不需要sychronized。



Reference:
•http://www.javamex.com/tutorials/synchronization_volatile.shtml
•http://www.javamex.com/tutorials/synchronization_volatile_java_5.shtml
•http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

=========================分割线2=================================



  恐怕比较一下volatile和synchronized的不同是最容易解释清楚的。volatile是变量修饰符,而synchronized则作用于一段代码或方法;看如下三句get代码:

int i1;             
int geti1() {return i1;} 
volatile int i2; 
int geti2()
 {return i2;} 
int i3;              
 synchronized int geti3() {return i3;} 




   geti1()得到存储在当前线程中i1的数值。多个线程有多个i1变量拷贝,而且这些i1之间可以互不相同。换句话说,另一个线程可能已经改变了它线 程内的i1值,而这个值可以和当前线程中的i1值不相同。事实上,Java有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它 自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的i1值是1,线程1里的i1值是2,线 程2里的i1值是3——这在线程1和线程2都改变了它们各自的i1值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。
  而 geti2()得到的是“主”内存区域的i2数值。用volatile修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经 volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的,volatile修饰的变量 存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。
  既然volatile关键字已经实现了线程间数据同步,又要 synchronized干什么呢?呵呵,它们之间有两点不同。首先,synchronized获得并释放监视器——如果两个线程使用了同一个对象锁,监 视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是,synchronized也同步内存:事实上,synchronized在“ 主”内存区域同步整个线程的内存。因此,执行geti3()方法做了如下几步:
1. 线程请求获得监视this对象的对象锁(假设未被锁,否则线程等待直到锁释放)
2. 线程内存的数据被消除,从“主”内存区域中读入(Java虚拟机能优化此步。。。[后面的不知道怎么表达,汗])
3. 代码块被执行
4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过geti3()方法不会改变变量值)
5. 线程释放监视this对象的对象锁
  因此volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。



=========================分割线3=================================



volatile关键字相信了解Java多线程的读者都很清楚它的作用。volatile关键字用于声明简单类型变量,如int、float、 boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。例如,下面的例子中的n就 不是原子级别的:

package  mythread;
 
public   class  JoinThread  extends  Thread
 {
      public   static volatile int  n  =   0 ;
     public   void  run()
     {
          for  ( int  i  =   0 ; i  <   10 ; i ++ )
              try 
        {
                 n  =  n  +   1 ;
                 sleep( 3 );  //  为了使运行结果更随机,延迟3毫秒 

            }
              catch  (Exception e)
             {
             }
     }
 
     public   static   void  main(String[] args)  throws  Exception
     {
 
        Thread threads[]  =   new  Thread[ 100 ];
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  建立100个线程 
            threads[i]  =   new  JoinThread();
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  运行刚才建立的100个线程 
            threads[i].start();
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  100个线程都执行完后继续 
            threads[i].join();
         System.out.println( " n= "   +  JoinThread.n);
     }
 } 


     如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面积代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别 的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子 操作:

n  =  n  +   1 ;
n ++ ;


      如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:

package  mythread;
 
public   class  JoinThread  extends  Thread
 {
      public   static int  n  =   0 ;
 
     public static   synchronized   void  inc()
     {
         n ++ ;
     }
      public   void  run()
     {
          for  ( int  i  =   0 ; i  <   10 ; i ++ )
              try 
            {
                 inc();  //  n = n + 1 改成了 inc(); 
                sleep( 3 );  //  为了使运行结果更随机,延迟3毫秒 

            }
              catch  (Exception e)
             {
             }
     }
 
     public   static   void  main(String[] args)  throws  Exception
     {
 
        Thread threads[]  =   new  Thread[ 100 ];
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  建立100个线程 
            threads[i]  =   new  JoinThread();
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  运行刚才建立的100个线程 
            threads[i].start();
          for  ( int  i  =   0 ; i  <  threads.length; i ++ )
              //  100个线程都执行完后继续 
            threads[i].join();
         System.out.println( " n= "   +  JoinThread.n);
     }
 } 


    上面的代码将n=n+1改成了inc(),其中inc方法使用了synchronized关键字进行方法同步。因此,在使用volatile关键字时要慎 重,并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++ 等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。





转载自:http://blog.csdn.net/orzorz/article/details/4319055
分享到:
评论

相关推荐

    java volatile 关键字实战

    java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...

    java volatile 关键字 学习

    java volatile 关键字 学习

    Java并发编程:volatile关键字解析

    ### Java并发编程:volatile关键字解析 #### 一、内存模型的相关概念 在深入了解`volatile`关键字之前,我们首先需要理解计算机内存模型的一些基本概念。在现代计算机系统中,CPU为了提高执行效率,会将频繁访问的...

    深入解析Java中的volatile关键字:原理、应用与实践

    在Java并发编程中,volatile关键字是一种轻量级的同步机制,它用于确保变量的可见性和有序性。本文将详细探讨volatile关键字的工作原理、使用场景以及如何在实际开发中正确使用volatile。 volatile关键字是Java并发...

    java里的volatile关键字详解

    "Java中的Volatile关键字详解" Java中的Volatile关键字详解是Java中的一种关键字,用于保证线程之间的可见性、原子性和有序性。下面是对Java中的Volatile关键字详解的知识点总结: 一、基本概念 1. 可见性:可见...

    Java volatile关键字详解.docx

    volatile

    Java Volatile关键字同步机制详解

    Java Volatile关键字同步机制详解 Java Volatile关键字是Java语言中的一种同步机制,它可以保证在多线程环境下变量的可见性和原子性。通过使用Volatile关键字,可以确保在多线程环境下对变量的修改是可见的,并且...

    java volatile关键字使用方法及注意事项

    volatile关键字在Java编程语言中扮演着重要的角色,特别是在多线程环境下的同步和可见性问题。它是Java内存模型(JMM)的一部分,用于确保共享变量的可见性和有序性,但不保证原子性。 1. **volatile的可见性**:当...

    Java并发volatile关键字.docx

    Java并发编程中,volatile关键字扮演着重要的角色,它是一种轻量级的同步机制,与synchronized相比,volatile在性能上更优,因为它不会导致线程阻塞。在深入理解volatile的关键特性之前,我们需要先了解Java内存模型...

    Java线程:volatile关键字

    Java 线程 volatile 关键字详解 Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。volatile 变量的同步性较差,但它有时更简单并且开销更低。volatile 变量可以被看作是一种 “程度较轻的 ...

    详解C中volatile关键字

    详解C中volatile关键字 volatile关键字是C语言中一个重要的关键字,它对变量的声明在不同编译环境下可能造成不同的结果。volatile关键字的作用是提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序...

    Java中volatile关键字实现原理

    Java中volatile关键字实现原理 volatile关键字是Java语言中的一种机制,用于保证变量在多线程之间的可见性。它是Java.util.concurrent包的核心,没有volatile就没有那么多的并发类供我们使用。本文详细解读一下...

    一文精通Java中的volatile关键字

    Java中的`volatile`关键字是多线程编程中的一个重要概念,它的主要作用是确保共享变量的可见性和禁止指令重排序。本文将深入探讨`volatile`的关键特性、工作原理以及使用注意事项。 1. 可见性: `volatile`关键字...

    java语言的volatile教程,java语言的volatile关键字是干什么用的

    java语言的volatile教程,java语言的volatile关键字到底怎么用

    java里的volatile关键字详解.pdf

    java里的volatile关键字详解.pdf

    C++中volatile关键字及常见的误解总结

    在C++中,volatile关键字的定义与Java中的volatile关键字不同。C++中的volatile关键字主要用于提供对特殊地址的稳定访问,而不是用于线程同步。 在编译器对代码的优化中,编译器可能会对代码进行修改,以提高代码的...

    深入理解 volatile 关键字.doc

    volatile关键字是Java语言的高级特性,它可以保证可见性和禁止指令重排序,但是要弄清楚其工作原理,需要先弄懂Java内存模型。 保证可见性 volatile关键字可以保证可见性,即当一个线程修改了某个变量时,其他所有...

    Java——volatile关键字详解

    Java中的`volatile`关键字是一个非常重要的并发控制工具,它提供了比`synchronized`关键字更为轻量级的同步机制。`volatile`关键字的主要作用是确保多线程环境下的可见性和禁止指令重排序,但不保证原子性。 **...

    深入了解Java中Volatile关键字

    深入了解Java中Volatile关键字 Volatile关键字是Java语言中的一种关键字,主要用于解决多线程编程中的可见性、原子性和有序性问题。本文将详细介绍Volatile关键字的相关知识,并通过代码帮助大家更好地理解和学习。...

    详解Java面试官最爱问的volatile关键字

    "Java面试官最爱问的volatile关键字详解" Java面试官最爱问的volatile关键字是Java并发编程中一个重要的概念,了解volatile关键字可以帮助开发者更好地理解Java内存模型(JMM)和Java并发编程的特性。本文将详细...

Global site tag (gtag.js) - Google Analytics