Java Volatile 变量的使用

本文深入讲解Java中Volatile关键字的作用及使用场景,并通过实例演示如何正确应用Volatile以解决多线程环境中变量可见性问题。

昨天有些闲暇时间,在网上看到了下面的文章。此文很简练,有助于对Volatile变量类型的理解。所以我翻译一下供那些对这种变量有兴趣的朋友们参考。另一方面,该文使用的例子得不到按该文说明的那样的结果,我看了一下,发现问题所在,本文最后会告诉你那个地方出了问题,而这一点也正是我们容易忽视的。

 

原文:

 Volatile keyword in Java
Author : Sutha
Date : Thu Feb 19th, 2009
Topic : java
 

This tips explains the use of volatile keyword in Java. The keyword volatile is used in the multithreaded environment.
Local Variables in the Thread

If you are working with the multi-threaded programming, the volatile keyword will be more useful. When multiple threads using the same variable, each thread will have its own copy of the local cache for that variable. So, when it's updating the value, it is actually updated in the local cache not in the main variable memory. The other thread which is using the same variable doesn't know anything about the values changed by the another thread. To avoid this problem, if you declare a variable as volatile, then it will not be stored in the local cache. Whenever thread are updating the values, it is updated to the main memory. So, other threads can access the updated value.
Volatile Example

 

原文例子:
package javabeat.samples;

class ExampleThread extends Thread {
 private volatile int testValue;
 public ExampleThread(String str){
  super(str);
 }
 public void run() {
  for (int i = 0; i < 3; i++) {
   try {
    System.out.println(getName() + " : "+i);
    if (getName().equals("Thread 1 "))
    {
     testValue = 10;
    }
    if (getName().equals("Thread 2 "))
    {
     System.out.println( "Test Value : " + testValue);
    }    
    Thread.sleep(1000);
   } catch (InterruptedException exception) {
    exception.printStackTrace();
   }
  }
 }
}
public class VolatileExample {
 public static void main(String args[]) {
  new ExampleThread("Thread 1 ").start();
  new ExampleThread("Thread 2 ").start();
 }
}

 

中文翻译:

本段文字讲述一下Javavolatile关键字的使用。该关键字用于多线程环境。

线程中的局部变量

如果你打算使用多线程编程,volatile关键字就显得有用武之地了。当在多个线程中使用相同的变量,那么每个线程都会在它自己的缓存里保有该变量的一个备份。这样,当该线程更新该变量值的时候,实际上它更新的不是定义在主内存中的变量本身,而是该线程自己缓存里的那个变量的备份值。而其他的也使用该变量的线程无从知道该变量是否已被别的线程更改过。如果你用volatile宣言这一变量,就可以避免该问题的发生。因为用volatile宣言的变量不在各线程自己的缓存里保存备份。不管什么时候任何线程更改该变量,就直接该变主内存内的变量本身,而不是变量的备份。这样其他的线程参照这个变量时,其值也是更新过的值。

本人补充解释:

从一般概念讲,线程thread不像process不具备自己独立内存空间,它们共享一个主内存空间,也就是原文中说的main memory.另一方面,每一个线程在执行的过程中是有它自己的缓存的,也就是原文中说的local cache. 

 

关于原文例子。如果你执行它,它的结果是:

Thread 1  : 0
Test Value print from Thread 1: 10
Thread 2  : 0
Test Value Test Value print from Thread 2: 0
Thread 2  : 1
Test Value Test Value print from Thread 2: 0
Thread 1  : 1
Test Value print from Thread 1: 10
Thread 2  : 2
Test Value Test Value print from Thread 2: 0
Thread 1  : 2
Test Value print from Thread 1: 10

 

 

看到的结果是thread 1和thread 2公用同一个用volatile 关键字修饰的testValue, 但在thread 1中该变的值thread 2却无法看到。这不是跟上边的解释有矛盾吗?我们回头看看程序,原来该变量被宣言成为了instance variable, 而两个线程被定义在了两个instance里。

其实只要把instance varilable 改为class varilable 就可以了。这样就确保了在主内存中只有一个该变量的instance,所有的线程都直接参照该volatile变量了。

 

Before:

private int testValue;

 

After:

static volatile int testValue;

 

修改后的程序执行结果:

Thread 1  : 0
Test Value print from Thread 1: 10
Thread 2  : 0
Test Value Test Value print from Thread 2: 10
Thread 1  : 1
Test Value print from Thread 1: 10
Thread 2  : 1
Test Value Test Value print from Thread 2: 10
Thread 1  : 2
Test Value print from Thread 1: 10
Thread 2  : 2
Test Value Test Value print from Thread 2: 10

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值