美文网首页
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 多线程运用

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