`
eric_hwp
  • 浏览: 126046 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

[转]Java多线程:慎重使用volatile关键字

 
阅读更多

Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。

validate关键字实现加锁的原理

在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。

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

  1. package mythread;  
  2.  
  3. public class JoinThread extends Thread  
  4. {  
  5.     public static volatile int n = 0;  
  6.     public void run()  
  7.     {  
  8.         for (int i = 0; i < 10; i++)  
  9.             try 
  10.         {  
  11.                 n = n + 1;  
  12.                 sleep(3); // 为了使运行结果更随机,延迟3毫秒  
  13.  
  14.             }  
  15.             catch (Exception e)  
  16.             {  
  17.             }  
  18.     }  
  19.  
  20.     public static void main(String[] args) throws Exception  
  21.     {  
  22.  
  23.         Thread threads[] = new Thread[100];  
  24.         for (int i = 0; i < threads.length; i++)  
  25.             // 建立100个线程  
  26.             threads[i] = new JoinThread();  
  27.         for (int i = 0; i < threads.length; i++)  
  28.             // 运行刚才建立的100个线程  
  29.             threads[i].start();  
  30.         for (int i = 0; i < threads.length; i++)  
  31.             // 100个线程都执行完后继续  
  32.             threads[i].join();  
  33.         System.out.println("n=" + JoinThread.n);  
  34.     }  
  35. }  
  36.        

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

n = n + 1;
n++;

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

  1. package mythread;  
  2.  
  3. public class JoinThread extends Thread  
  4. {  
  5.     public static int n = 0;  
  6.  
  7.     public static synchronized void inc()  
  8.     {  
  9.         n++;  
  10.     }  
  11.     public void run()  
  12.     {  
  13.         for (int i = 0; i < 10; i++)  
  14.             try 
  15.             {  
  16.                 inc(); // n = n + 1 改成了 inc();  
  17.                 sleep(3); // 为了使运行结果更随机,延迟3毫秒  
  18.  
  19.             }  
  20.             catch (Exception e)  
  21.             {  
  22.             }  
  23.     }  
  24.  
  25.     public static void main(String[] args) throws Exception  
  26.     {  
  27.  
  28.         Thread threads[] = new Thread[100];  
  29.         for (int i = 0; i < threads.length; i++)  
  30.             // 建立100个线程  
  31.             threads[i] = new JoinThread();  
  32.         for (int i = 0; i < threads.length; i++)  
  33.             // 运行刚才建立的100个线程  
  34.             threads[i].start();  
  35.         for (int i = 0; i < threads.length; i++)  
  36.             // 100个线程都执行完后继续  
  37.             threads[i].join();  
  38.         System.out.println("n=" + JoinThread.n);  
  39.     }  
  40. }  

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

 

使用到的地方:

  1. 当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

使用不合适的地方:

  1. 效率要求高的项目,由于使用屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
  2. 当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。

分享到:
评论

相关推荐

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

    使用`volatile`关键字可以确保在多个线程试图初始化同一个对象时,能够正确地处理可见性和有序性问题。 总结来说,`volatile`关键字是Java并发编程中一个非常重要的概念。它不仅解决了多线程环境下的可见性问题,还...

    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 变量。volatile 变量的同步性较差,但它有时更简单并且开销更低。volatile 变量可以被看作是一种 “程度较轻的 ...

    深入多线程之:内存栅栏与volatile关键字的使用分析

    以前我们说过在一些简单的例子中,比如为一个字段赋值或递增该字段,我们需要对线程进行同步,虽然lock可以满足我们的需要,但是一个竞争锁一定会导致阻塞,然后忍受线程上下文切换和调度的开销,在一些高并发和性能...

    Java多线程编程总结

    Java线程:volatile关键字 Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-...

    java多线程编程之慎重使用volatile关键字

    在Java多线程编程中,volatile关键字扮演着重要的角色,它确保了被声明为volatile的变量在多个线程之间的可见性。然而,尽管volatile能够提供一定程度的线程安全,但并不能保证所有操作都是原子性的。这正是为什么在...

    一文精通Java中的volatile关键字

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

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

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

    Java多线程 volatile关键字详解

    Java多线程volatile关键字详解 Java多线程volatile关键字详解主要介绍了Java多线程volatile关键字的应用和原理。volatile是一种轻量同步机制,可以确保变量的可见性和顺序性,但不保证原子性。 volatile关键字的...

    多方面解读Java中的volatile关键字.rar

    下面我们将从多个角度深入解读Java中的`volatile`关键字。 1. **可见性**:`volatile`关键字确保了变量的修改对所有线程是立即可见的。当一个线程修改了`volatile`变量后,其他线程能够立即看到这一变化,而无需...

    java里的volatile关键字详解

    3. 有序性:Java语言提供了volatile 和synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized是由“一个变量在同一个时刻只允许一条线程对其进行...

    java线程详解

    Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、单任务延迟连接池 六、自定义线程池 Java线程:新特征-有返回值的线程...

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

    "Java面试官最爱问的...volatile关键字是Java并发编程中一个重要的概念,了解volatile关键字可以帮助开发者更好地理解Java内存模型(JMM)和Java并发编程的特性,并且可以更好地解决多线程环境下的共享变量问题。

    Java 理论与实践: 正确使用 volatile 变量 线程同步

     使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。  由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此...

    Java并发教程之volatile关键字详解

    Java并发教程之volatile关键字详解 Java并发教程之volatile关键字的相关资料,对大家学习或者使用Java具有一定的参考学习价值。...volatile关键字是解决多线程问题的重要工具,但是需要正确地使用和理解其原理。

    深入了解Java中Volatile关键字

    2. 使用volatile关键字在多线程环境下:volatile关键字可以用于多线程环境下,保证线程之间操作的可见性和有序性。 四、示例代码 以下是一个示例代码,演示了volatile关键字的使用: ```java public class ...

    java volatile 关键字 学习

    java volatile 关键字 学习

    Java多线程并发编程 Volatile关键字

    Java中的`volatile`关键字在多线程并发编程中扮演着重要的角色,但常常被误解。在J2EE环境中,程序员可能对其有更多了解,而在Android开发中,它并不那么常见,因此导致了一些开发者对它的误用。理解`volatile`的...

Global site tag (gtag.js) - Google Analytics