[网摘]CSDN上的讨论

回复1:

        首先每个线程都有自己一个工作内存区,多个线程共享一个主内存区。线程中的本地变量存在自己的内存区中,如for(int   i=0;i<100;i++){this.i=i;},其中i就存在线程工作内存中,即每个线程都有一个,不用也不能加volatile关键字,this.i就是共享变量。而共享的变量就存在主内存区里,但Java线程为了提高效率,会把共享变量拷贝到自己的工作区中,这就产生了变量一致性的问题。  
  java提供的一种方法是互斥访问,互斥访问会在加锁和解锁中维持变量的一致性,另一种就是volatile关键字。  
   
  java   language   specification中的一个例子,有类如下:  
 

class   Test   {   
      static   int   i   =   0,   j   =   0;   
      static   void   one()   {   i++;   j++;   }   
      static   void   two()   {   
                                            System.out.println("i="   +   i   +   "   j="   +   j);   
                                          }   
  }


  有两个线程,一个不停调用   one(),一个不停调用   two(),则有可能出现这种情况,打印出来的j比i还大。因为这时线程对共享变量的更新是无序的。  
  1.使用同步方法:  

class   Test   {   
      static   int   i   =   0,   j   =   0;   
      static   synchronized   void   one()   {   i++;   j++;   }   
      static   synchronized   void   two()   {   
                                                                      System.out.println("i="   +   i   +   "   j="   +   j);   
                                                                      }   
  }


  这就不用我介绍了,i和j始终一样大。  
  2.使用volatile  
 

class   Test   {   
      static   volatile   int   i   =   0,   j   =   0;   
      static   void   one()   {   i++;   j++;   }   
      static   void   two()   {   
                                            System.out.println("i="   +   i   +   "   j="   +   j);   
                                            }   
  }


  这样能允许one()和two()并发执行,同时使one()如字面一样执行。这一般能使打印出来的j不会大于i,在更新j之前会先更新i。但有可能打印出来的j比i大很多,因为one()可能在two获取i和j之间执行了很多次。  
   
  说明一下:  
          java   language   specification中的例子不好,有点晦涩,但我认为volatile的作用就是保证任何时候主内存的i都大于等于j。two()中出现j比i大很多,只是因为它访问的是不同时刻的主内存。  
          还有一点,就是volatile能防止编译器对变量进行优化,每次共享变量都到主内存。如果线程不到主内存中读,变量的值就会不正确。

 

回复2:

更确切一点的说,在线程改变其自身工作区中的volatile变量时,会强制立即将该值更新到主工作区中,从而保证数据的一致性。synchronized和volatile结合使用能保证多线程的完全同步。

 

回复3:

还有遗漏了一点没说,线程在试图读取一个volatile变量时,会从主内存区中读取最新的值