volatile关键字

来源:互联网 发布:怎么检查网络连接状态 编辑:程序博客网 时间:2024/05/21 23:34

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。


/*
 *
 如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面积代码时,很多时侯输出的n都小于1000,
 这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,
 那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
 n = n + 1;
 n++;
 如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:
 *
 */
public class JoinThread extends Thread {
 public static volatile int n = 0;

 // public static int n = 0;

 public void run() {
  for (int i = 0; i < 10; i++)
   try {
    n = n + 1;
    // inc();
    sleep(3);
    // 为了使运行结果更随机,延迟3毫秒
   } catch (Exception e) {
   }
 }

 public static synchronized void inc() {
  n++;
 }

 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);
 }
}

原创粉丝点击