在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。
public class TestVolatile { /* * 执行环境——jdk版本:jdk1.6.0_31 ,内存 :3G cpu:x86 2.4G */ public static int count = 0; public static void inc() { // 这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) {} count++; } public static void main(String[] args) { // 同时启动1000个线程,去进行i++计算,看看实际结果 for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { TestVolatile.inc(); } }).start(); } // 这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:TestVolatile.count=" + TestVolatile.count); } } // 运行结果:Counter.count=995
public class TestVolatile { public volatile static int count = 0; public static void inc() { // 这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) { } count++; } public static void main(String[] args) { // 同时启动1000个线程,去进行i++计算,看看实际结果 for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { TestVolatile.inc(); } }).start(); } // 这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:TestVolatile.count=" + TestVolatile.count); } } //运行结果:Counter.count=992
read and load:从主存复制变量到当前工作内存。
use and assign:执行代码,改变共享变量值 。
store and write:用工作内存数据刷新主存相关内容。
其中use and assign 可以多次出现。
但是这一些操作并不是原子性,也就是 在read load之后,如果主内存count变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以会出现多线程并发问题。
volatile关键字用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A) 。
Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。如果配合Java 5增加的atomic wrapper classes,对它们的increase之类的操作就不需要sychronized。
volatile是变量修饰符,而synchronized则作用于一段代码或方法。volatile只是在线程内存和“主”内存间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。
volatile关键字用于声明简单类型变量,如int、float、 boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。
当变量的值由自身的上一个决定时,如n=n+1、n++ 等,就不是原子操作。只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。