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

可见性和volatile -- Java并发

阅读更多

 

可见性是Java虚拟机上定义的逻辑上的偏序关系。通常指某些操作的结果对后续的其他操作必须是可见的。详细内容参见《Java Concurrency In Practice》,这部分内容通常被称为Java Memory Model,与操作系统Memory Model概念类似。主要通过一个简单程序说明一下,相当于一个学习总结。下面是程序

参考Doug Lea的JSR133 CookBook  http://gee.cs.oswego.edu/dl/jmm/cookbook.html

 

 

/**
 *Not Thread Safe
 */
public class Counter {

    private int count = 0;

    public void increment() {
        count++;
    }

    public int get() {
        return count;
    }
}

 程序很简单,但不是线程安全的问题很多。包括reorder,可见性,还有最基本的互斥执行,都没得到保证

 

 1. increment方法不是原子操作,自增实际上对应多个机器指令。所以并发情况下,会出现不正确结果。

那加上synchronized又如何。

 

 

 

public class Counter {

    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int get() {
        return count;
    }
}

 2.我知道肯定有人会说get执行时没有加锁,读操作也需要加锁,确实如此,注意这一点,synchronized的操作造成的结果对其他执行相同synchronized操作的线程是可见的,但由于get没有加锁,所以不能保证increment对该get操作可见。假设count是0执行了一次increment之后get到的可能还是0,因为increment的操作造成的结果也许get线程还不能看到。此外还有reordering造成的问题,但是这种情形出现几率很小。有兴趣请去看JSR 133 http://gee.cs.oswego.edu/dl/jmm/cookbook.html

现在看最后一个版本(抱歉不是都加synchronized版本)

 

 

 

public class Counter {

    private volatile int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int get() {
        return count;
    }
}

 3.根据brain geotz 同学的说法,上面的代码是线程安全的。

实际上它确实是线程安全的。因为volatile同样有可见性保证,这保证increment操作的结果对所有count的读取操作都是可见的。同样synchronized和volatile在虚拟机上都有reorder的约束,所以可以保证是线程安全的。关于更多的可见性和reorder同样参考JSR133http://gee.cs.oswego.edu/dl/jmm/cookbook.html

 

注意,这样的客户端调用是不正确的。

 class Wrapper{
        private Counter counter = new Counter();
        
        public int incrementAndGet(){
            counter.increment();
            return counter.get();
        }
    }
 Counter只保证单个get和increment操作是正确,但组合操作是不能保证线程安全的。
分享到:
评论
2 楼 jilen 2011-05-20  
francis.xjl 写道
++一般情况下认为不是原子的,那么也就是说++过程分拆成几个指令来完成。而get()没有sychronized约束,也就是可以获取++的中间结果。volatile保证的是可见性,但似乎volatile无法保证get()得到的不是++的中间结果。

不知道我的理解是否正确,请指教。

你觉得++操作会拆成几个指令呢。我想内存操作只要一次取值,一次写。increment只发生了取值,没有写,那么可以认为,数据没有发生变化,这个时候不阻塞get是可以理解了。如果increment发生写操作,之后任意时间内get都会获取到最新的值,所以认为是一致的。

而且操作系统也有内存模型,不会出现正在读一块内存同时有其他线程修改这块内存值。对于int,其实一条取值的指令就足够了。如果是double这些,我想操作系统会保证写和读的安全,当然,这块我并不确定。不知道是否回答了你的问题。
1 楼 francis.xjl 2011-05-20  
++一般情况下认为不是原子的,那么也就是说++过程分拆成几个指令来完成。而get()没有sychronized约束,也就是可以获取++的中间结果。volatile保证的是可见性,但似乎volatile无法保证get()得到的不是++的中间结果。

不知道我的理解是否正确,请指教。

相关推荐

    计算机后端-Java-Java高并发从入门到面试教程-并发基础.zip

    此外,Java的 volatile 关键字可以确保共享变量的可见性,防止线程之间的缓存数据不一致。 Java并发工具类也是学习的重点。比如,Semaphore信号量可以控制同时访问特定资源的线程数量,CountDownLatch可以用于线程...

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

    2. **单例模式中的双重检查锁定**:在实现线程安全的单例模式时,`volatile`关键字可以用来保证实例创建过程中的可见性和有序性,避免多线程环境下可能出现的问题。 3. **懒汉式初始化**:在某些情况下,为了避免...

    计算机后端-Java-Java高并发从入门到面试教程-课程准备.zip

    - **Java内存模型(JMM)**:理解JMM对变量可见性、有序性和原子性的保证。 - **volatile关键字**:学习volatile的语义,如何解决线程间通信问题。 - **指令重排序**:了解编译器和处理器为了优化性能可能进行的...

    Java并发编程系列- volatile

    总的来说,`volatile`关键字在Java并发编程中起到的作用是确保共享变量的即时可见性和防止指令重排,但并不保证操作的原子性。理解并合理使用`volatile`可以有效地提升多线程程序的并发性能,但同时也需要注意它的...

    Java 多线程与并发(1-26)-Java 并发 - 理论基础.pdf

    Java 中的多线程机制的主要目标是解决并发问题,包括可见性、原子性和有序性三个方面。可见性问题是指一个线程对共享变量的修改,另一个线程不能立即看到。原子性问题是指一个操作或者多个操作要么全部执行并且执行...

    计算机后端-Java-Java高并发从入门到面试教程-发课程资料.zip

    - 了解Java内存模型的可见性和有序性,理解volatile关键字的作用。 8. **并发性能优化** - **死锁**:理解死锁的概念,如何避免和检测死锁。 - **线程池调优**:根据业务需求合理配置线程池大小,避免资源浪费。...

    计算机后端-Java-Java高并发从入门到面试教程-存思路.zip

    - **JMM(Java Memory Model)**:理解变量的可见性和有序性问题。 - **volatile**:学习其保证可见性及禁止指令重排序的作用。 - **原子变量类**:如`AtomicInteger`、`AtomicLong`等,无锁编程的实现。 6. **...

    Java并发volatile可见性的验证实现

    在Java并发编程中,volatile关键字扮演着非常重要的角色,它可以确保变量的可见性和原子性。在多线程环境下,volatile关键字可以确保变量的修改对其他线程是可见的。本文将通过示例代码详细介绍Java并发volatile可见...

    计算机后端-Java-Java高并发从入门到面试教程-容思路.zip

    接下来,我们要探讨Java并发工具类,如Semaphore信号量、CyclicBarrier回环栅栏、CountDownLatch倒计时器等,这些工具可以帮助我们更好地管理和协调并发任务。例如,Semaphore用于限制同时访问特定资源的线程数量,...

    计算机后端-Java-Java高并发从入门到面试教程-课程总结.zip

    14. volatile和synchronized在JMM中的作用:分析这两个关键字如何确保可见性和有序性。 六、并发设计模式 15. 生产者消费者模式:通过阻塞队列实现线程间的协同工作。 16. 状态机模式:在并发环境下管理对象状态的...

    java并发编程2

    - ** volatile** 关键字 用于保证变量的可见性,但不保证原子性。 - **Lock接口与ReentrantLock** 提供了比`synchronized`更细粒度的锁控制,可以实现公平锁和非公平锁,以及可中断和可重入的特性。 4. **并发...

    JAVA并发编程艺术pdf版

    《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...

    计算机后端-Java-Java高并发从入门到面试教程-可.zip

    本教程将引导你从零基础开始,逐步掌握Java并发编程的核心概念和技术,助你在面试中脱颖而出,提升职场竞争力。 首先,我们需要理解什么是并发。并发是指在一段时间内,多个任务看似同时进行的状态。在Java中,实现...

    A-JUC-JVM-Java并发知识..pdf

    Java并发编程包(java.util.concurrent,简称JUC)封装了大量用于高并发编程的工具类和接口,其中涉及了线程池、阻塞队列、同步器、原子操作类等。在并发环境下,可以有效降低线程创建和管理的复杂性。 #### Java...

    计算机后端-Java-Java高并发从入门到面试教程-.C组件拓展.zip

    `volatile`关键字确保变量在多个线程间可见性。`Lock`接口和`ReentrantLock`类提供了更细粒度的锁控制。`Semaphore`、`CountDownLatch`、`CyclicBarrier`等同步工具类在多线程协调中也发挥着重要作用。 3. **并发...

    ( Java并发程序设计教程.zip )高清版 PDF

    JMM规定了线程如何访问共享内存,如何保证可见性、原子性和有序性。书中会详细阐述 volatile 的工作原理,以及如何利用其确保线程间的正确通信。 此外,Java并发集合框架是另一个重要章节。它包含一系列优化过的...

    Java 多线程与并发-Java并发知识体系详解.pdf

    `volatile`关键字则保证了变量的可见性和有序性,但不保证原⼦性。而`final`关键字保证了变量的不可变性,防止被重新赋值,对于方法来说,final方法不能被子类重写。 线程的状态包括新建、就绪、运行、阻塞和死亡。...

    Java 多线程与并发(5-26)-关键字- volatile详解.pdf

    Java中的`volatile`关键字是多线程编程中一个重要的概念,它主要解决了两个核心问题:可见性和有序性。在Java内存模型(JMM)中,`volatile`关键字确保了线程之间的通信更加有效和安全。 **一、防止指令重排序** ...

    《java 并发编程实战高清PDF版》

    书中详细阐述了可见性、原子性和有序性这些概念,并通过`volatile`关键字和`final`修饰符的使用来演示它们的作用。 除了锁,Java还提供了其他同步机制,如`java.util.concurrent`包下的并发工具类。其中包括`...

Global site tag (gtag.js) - Google Analytics