`
Copperfield
  • 浏览: 260381 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
C407adc3-512e-3a03-a056-ce4607c3a3c0
java并发编程陷阱
浏览量:25147
社区版块
存档分类

并发编程陷阱系列(四)volatile与变量脏读

 
阅读更多

预备知识:

每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图描述这写交互:



在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。

 

把变量声明为volatile(不稳定的),相当于指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。

volatile不能和final连用:It is a compile-time error if a final variable is also declared volatile.

 

为什么要使用Volatile
Volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度。

 

举例:

 

public class VolatileTest {
    public static volatile int race = 0;

    public static void increase() {
        race++;
    }

    public static int THREADS_COUNT = 20;

    public static void main(String[] args) {
        Thread[] threads = new Thread[THREADS_COUNT];
        for (int i = 0; i < THREADS_COUNT; i++) {
            threads[i] = new Thread(new Runnable() {
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        increase();
                    }
                }
            });
            threads[i].start();            

        }
        while (Thread.activeCount() > 1) {            
            Thread.yield();
            System.out.println(race);
        }

    }
}

 

 

我们的预期是输出200000,但大多数情况下输出的值都比200000小。

 

观察increase的byte code:

 

public static void increase();
  Code:
   0:   getstatic       #11; //Field race:I
   3:   iconst_1
   4:   iadd
   5:   putstatic       #11; //Field race:I
   8:   return

 

 当getstatic指令把race的值取到操作栈顶时,volatile 关键字保证了race的值在此时是正确的,但是在执行iconst_1,iadd这些指令的时候,其他线程可能已经把race的值加大了。而在操作栈顶的值变成了过期的数据,所以putstatic指令执行后就可能把较小的race值同步到内存中了。

 

应用volatile变量的四个原则:
      (1)写入变量不依赖此变量的值,或者只有一个线程修改此变量
      (2)变量的状态不需要与其它变量共同参与不变约束
      (3)访问变量不需要加锁
      (4)由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

参考:

http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

  • 大小: 57.8 KB
分享到:
评论

相关推荐

    java 并发编程的艺术pdf清晰完整版 源码

    9. **并发编程最佳实践**:最后,书中会提供一些并发编程的最佳实践,帮助读者避免常见的并发陷阱,写出更健壮、更高效的代码。 通过阅读《Java并发编程的艺术》这本书,开发者不仅可以掌握Java并发编程的基础知识...

    Java并发编程书籍高清版

    例如,书中详细介绍了synchronized关键字的作用、 volatile变量的使用、线程池的创建与管理,以及Future接口和ExecutorService在处理异步任务时的应用。 其次,《java并发编程的艺术》是一本针对Java程序员的实用...

    并发编程一之synchronized和volatile.rar

    本资源"并发编程一之synchronized和volatile.rar"提供了多个示例代码(demo1到demo12),帮助我们深入理解这两个关键字的功能与用法。 1. **synchronized关键字**: - **互斥性**:synchronized可以确保同一时间...

    java并发编程

    Java并发编程是Java开发者必须掌握的关键技能之一,它涉及到如何在多线程环境中高效、安全地执行程序。并发编程能够充分利用多核处理器的计算能力,提高应用程序的响应速度和整体性能。《Java编程并发实战》这本书是...

    java并发编程实战(中文+高清版)pdf及源码

    源码分析部分则让读者有机会亲手实践,通过阅读和运行书中提供的示例代码,可以更直观地理解并发编程的各种技巧和陷阱。这些源码可以帮助读者在实际项目中应用所学知识,解决实际问题。 在阅读《Java并发编程实战》...

    Java并发编程:设计原则与模式(第二版).rar

    3. **线程安全**:线程安全是并发编程中的重要主题,书中会探讨各种线程安全的实现策略,如使用`synchronized`关键字、`volatile`变量、`final`修饰以及线程局部变量(`ThreadLocal`)。 4. **并发集合**:Java的...

    JAVA并发编程实践(英文版+中文1-9章)

    《JAVA并发编程实践》是一本深入探讨Java多线程与并发控制的权威著作。这本书针对Java程序员,旨在帮助他们理解和掌握如何在并发环境中编写高效、可靠的代码。在Java的世界里,并发编程是不可或缺的一部分,特别是在...

    Java并发编程实践 高清扫描版

    《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。并发和多线程是现代计算机系统中不可或缺的部分,特别是在Java这样的多线程支持语言中。本书详细介绍了如何在Java环境中有效地设计和实现...

    java并发编程库

    volatile保证了变量的内存可见性,也就是说,对一个volatile变量的修改,对其他线程立即可见。尽管volatile不能保证操作的原子性,但其在某些场景下能减少锁的使用,从而提高性能。 J.U.C中的并发集合,如...

    java并发编程电子书

    《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要...通过阅读《Java并发编程实践》,开发者可以学习到如何编写高效、稳定的并发程序,避免并发陷阱,提升软件质量。同时,书中实例丰富,便于实践和理解。

    java高并发程序设计(原版电子书)

    1. **并发基础**:首先,书中会介绍并发编程的基本概念,如线程、进程、同步与通信机制,以及Java中的线程API,如`Thread`类和`Runnable`接口。 2. **线程管理**:讨论如何创建、启动、停止和控制线程,包括线程池...

    《java并发编程的核心方法和框架》

    - **Java Concurrency in Practice**(JCIP):经典的并发编程指南,书中介绍了大量并发编程的最佳实践和陷阱。 - **Akka**和**Quasar**:基于Actor模型和纤程( Fiber)的高性能并发框架,提供更高级别的抽象来...

    JAVA并发编程实践

    - **并发编程陷阱与优化技巧**: - 避免过度同步; - 合理使用无锁算法; - 选择合适的并发容器; - 适时采用线程池。 ### 总结 《JAVA并发编程实践》一书深入浅出地介绍了Java并发编程的核心概念和技术细节,...

    [Java并发编程实践].(Java.Concurrency.in.Practice).Brian.Goetz.文字版.rar下载地址

    通过学习《Java并发编程实践》,开发者可以更深入地理解Java并发机制,提高代码的并发性能,避免常见的并发陷阱,从而写出更高效、更可靠的并发程序。这本书是Java并发编程的必读之作,无论你是初学者还是有经验的...

    [Java并发编程实践].(Java.Concurrency.in.Practice) 下载

    9. **并发编程的最佳实践**:书中总结了一系列的并发编程最佳实践,如最小化锁的粒度、避免过度同步等,帮助开发者编写出更健壮、可维护的并发程序。 通过阅读《Java并发编程实践》,读者不仅可以深入了解Java并发...

    JAVA并发编程实践中文版

    最后,作者们分享了一些最佳实践和陷阱,帮助开发者避免常见的并发编程错误。 总的来说,《JAVA并发编程实践》这本书全面覆盖了Java并发编程的各个方面,无论是理论知识还是实战技巧,都是Java开发者不可或缺的参考...

    Java并发编程实践中文

    这本书详细介绍了Java并发编程的基础知识,高级技巧以及实战经验,旨在帮助读者掌握如何有效地利用多核处理器的能力,提高程序性能,同时避免并发编程中常见的陷阱。 并发编程是现代软件开发中的重要组成部分,特别...

    java 并发编程实战

    这本书详细介绍了如何在Java环境中有效地设计和实现并发程序,帮助开发者避免并发编程中常见的陷阱。 首先,书中会讲解Java并发编程的基础概念,包括线程、进程、同步和异步的概念。线程是操作系统分配CPU时间的...

Global site tag (gtag.js) - Google Analytics