美文网首页
volatile 多线程运用

volatile 多线程运用

作者: Skypew | 来源:发表于2017-05-25 16:50 被阅读24次

Java含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。
其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。

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

线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全。

您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:

  • 对变量的写操作不依赖于当前值。
  • 该变量没有包含在具有其他变量的不变式中。

第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)

只有在状态真正独立于程序内其他内容时才能使用 volatile

可以使用 的情况 案例

1:状态标志
也许实现 volatile 变量的规范使用仅仅是使用一个布尔状态标志,用于指示发生了一个重要的一次性事件,例如完成初始化或请求停机

2:一次性安全发布(one-time safe publication)
缺乏同步会导致无法实现可见性,这使得确定何时写入对象引用而不是原语值变得更加困难。在缺乏同步的情况下,可能会遇到某个对象引用的更新值(由另一个线程写入)和该对象状态的旧值同时存在。(这就是造成著名的双重检查锁定(double-checked-locking)问题的根源,其中对象引用在没有同步的情况下进行读操作,产生的问题是您可能会看到一个更新的引用,但是仍然会通过该引用看到不完全构造的对象)。
实现安全发布对象的一种技术就是将对象引用定义为 volatile 类型。清单 3 展示了一个示例,其中后台线程在启动阶段从数据库加载一些数据。其他代码在能够利用这些数据时,在使用之前将检查这些数据是否曾经发布过。


清单 3. 将 volatile 变量用于一次性安全发布

public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;
 
    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}
 
public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}

如果 theFlooble 引用不是 volatile 类型,doWork() 中的代码在解除对 theFlooble 的引用时,将会得到一个不完全构造的 Flooble。
该模式的一个必要条件是:被发布的对象必须是线程安全的,或者是有效的不可变对象(有效不可变意味着对象的状态在发布之后永远不会被修改)。volatile 类型的引用可以确保对象的发布形式的可见性,但是如果对象的状态在发布后将发生更改,那么就需要额外的同步

清单 4. 将 volatile 变量用于多个独立观察结果的发布

public class UserManager {
    public volatile String lastUser;
 
    public boolean authenticate(String user, String password) {
        boolean valid = passwordIsValid(user, password);
        if (valid) {
            User u = new User();
            activeUsers.add(u);
            lastUser = user;
        }
        return valid;
    }
}

该模式是前面模式的扩展;将某个值发布以在程序内的其他地方使用,但是与一次性事件的发布不同,这是一系列独立事件。这个模式要求被发布的值是有效不可变的 —— 即值的状态在发布后不会更改。使用该值的代码需要清楚该值可能随时发生变化。

更多参考 :
https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

相关文章

  • volatile 多线程运用

    Java含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安...

  • volatile的作用

    Volatile的介绍: 使用volatile的原因: 用在多线程,目的同步变量 Volatile变量相对于锁更简...

  • volatile和synchronized的区别

    volatile volatile保证了多线程之间的可见性。用volatile修饰的变量,在多个线程中都可以读到最...

  • 【多线程进阶并发编程二】volatile 应用

    volatile简介     volatile主要作用就是使变量在多线程间可见,理解volatilet特性的最好的...

  • java 高并发中volatile的实现原理

    java 高并发中volatile的实现原理 摘要: 在多线程并发编程中synchronized和Volatile...

  • 多线程并发

    多线程并发必须掌握的相关概念:多线程:Thread、ThreasPool线程安全:volatile ,syncho...

  • Java中的volatile

    Java中的volatile 在多线程并发编程中Synchronized 和 Volatile都扮演者重要的角色,...

  • 多线程编程那些事

    多线程编程那些事 标签:HPC、多线程、JMM、Volatile、锁、CPU多核构架、Happens before...

  • volatile浅析

    volatile可以理解为轻量级的synchronized,因为多线程并发访问volatile变量时,不会引起线程...

  • 20170206-多线程同步volatile与Condition

    多线程同步 201612 volatile 对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程...

网友评论

      本文标题:volatile 多线程运用

      本文链接:https://www.haomeiwen.com/subject/rujzxxtx.html