`

volatile 的高级模式

    博客分类:
  • JAVA
 
阅读更多
前面几节介绍的模式涵盖了大部分的基本用例,在这些模式中使用 volatile 非常有用并且简单。这一节将介绍一种更加高级的模式,在该模式中,volatile 将提供性能或可伸缩性优势。
volatile 应用的的高级模式非常脆弱。因此,必须对假设的条件仔细证明,并且这些模式被严格地封装了起来,因为即使非常小的更改也会损坏您的代码!同样,使用更高级的 volatile 用例的原因是它能够提升性能,确保在开始应用高级模式之前,真正确定需要实现这种性能获益。需要对这些模式进行权衡,放弃可读性或可维护性来换取可能的性能收益 —— 如果您不需要提升性能(或者不能够通过一个严格的测试程序证明您需要它),那么这很可能是一次糟糕的交易,因为您很可能会得不偿失,换来的东西要比放弃的东西价值更低。
模式 #5:开销较低的读-写锁策略
目前为止,您应该了解了 volatile 的功能还不足以实现计数器。因为 ++x 实际上是三种操作(读、添加、存储)的简单组合,如果多个线程凑巧试图同时对 volatile 计数器执行增量操作,那么它的更新值有可能会丢失。
然而,如果读操作远远超过写操作,您可以结合使用内部锁和 volatile 变量来减少公共代码路径的开销。清单 6 中显示的线程安全的计数器使用 synchronized 确保增量操作是原子的,并使用 volatile 保证当前结果的可见性。如果更新不频繁的话,该方法可实现更好的性能,因为读路径的开销仅仅涉及 volatile 读操作,这通常要优于一个无竞争的锁获取的开销。

清单 6. 结合使用 volatile 和 synchronized 实现 “开销较低的读-写锁”

              
@ThreadSafe
public class CheesyCounter {
    // Employs the cheap read-write lock trick
    // All mutative operations MUST be done with the 'this' lock held
    @GuardedBy("this") private volatile int value;

    public int getValue() { return value; }

    public synchronized int increment() {
        return value++;
    }
}


之所以将这种技术称之为 “开销较低的读-写锁” 是因为您使用了不同的同步机制进行读写操作。因为本例中的写操作违反了使用 volatile 的第一个条件,因此不能使用 volatile 安全地实现计数器 —— 您必须使用锁。然而,您可以在读操作中使用 volatile 确保当前值的可见性,因此可以使用锁进行所有变化的操作,使用 volatile 进行只读操作。其中,锁一次只允许一个线程访问值,volatile 允许多个线程执行读操作,因此当使用 volatile 保证读代码路径时,要比使用锁执行全部代码路径获得更高的共享度 —— 就像读-写操作一样。然而,要随时牢记这种模式的弱点:如果超越了该模式的最基本应用,结合这两个竞争的同步机制将变得非常困难。
分享到:
评论

相关推荐

    volatile使用详解

    在 `release` 模式下,如果没有使用 `volatile`,第二次读取 `i` 的值时可能不会从内存中重新读取,而是使用之前缓存的值。但使用了 `volatile` 后,每次访问 `i` 都会从内存中重新读取,确保获取的是最新值。 ####...

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

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

    volatile的作用

    `volatile`的高级用法 #### (3.1) 确保可见性 当多个线程访问同一个变量时,为了保证数据的一致性和可见性,可以使用`volatile`关键字。例如,在多线程环境中,如果一个线程修改了一个变量,而另一个线程需要读取...

    volatile的使用1

    例如,作为共享状态的标志,用于多线程间的通信,例如单例模式的双重检查锁定(Double-Check Locking)中,volatile可以确保线程安全地初始化单例。 5. **原理**:在底层实现上,volatile变量在汇编代码中会包含一...

    设计模式之单例模式(结合工厂模式)

    DCL模式结合了两者优点,既保证了线程安全,又实现了延迟初始化。 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,当创建对象时,我们不会对客户端暴露创建逻辑,而是提供一个接口...

    violate java-Java 之 volatile 超级详解

    3. 简单计数器:如果计数器的增加操作是线程安全的(例如,仅包含读和写操作),可以使用`volatile`来实现简单的计数器。 需要注意的是,虽然`volatile`提供了轻量级的同步机制,但在设计多线程程序时,应优先考虑...

    线程安全的单例模式

    ### 线程安全的单例模式详解 #### 一、单例模式简介 单例模式(Singleton Pattern)是软件开发中最常用的创建型设计模式之一,它的主要目标是确保一个类只有一个实例,并提供一个全局访问点。单例模式在很多场景下...

    Java volatile的适用场景实例详解

    Java volatile的适用场景实例详解 Java volatile 关键字是 Java 并发编程中的一种...volatile 变量是一种非常有用的线程安全机制,但是它的使用需要非常小心,需要遵守一定的使用条件和模式,以避免出现线程安全问题。

    设计模式.pdf_电子版_pdf版

    设计模式概述与 Singleton 模式详解 在软件设计中,设计模式是解决问题的方案,学习现有的设计模式可以做到经验复用。拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。 设计模式可以...

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

    - 单例模式中的双重检查锁定(Double-Check Locking),确保实例化过程线程安全。 - 标记共享状态,比如在标志变量中,表示某个条件是否满足,如`isRunning`。 - 并发量小、更新频率低的共享计数器,如访问次数...

    饿汉模式和懒汉模式

    饿汉模式是在类加载时就完成了初始化,因此类加载比较慢,但获取单例对象的速度快,且线程安全。由于实例在类加载时已经创建,所以不会出现多线程下的并发问题。饿汉模式的实现代码通常如下: ```java public class...

    深入探讨Java多线程中的volatile变量共6页.pd

    在实际应用中,volatile常用于简单的状态标记,如标志位(例如:一个线程是否应该继续运行),或者是单例模式中的Double-Check Locking(双重检查锁定)中用来确保实例化过程的正确性。不过,需要注意的是,过度依赖...

    Java常用的3中设计模式代码即工厂模式、单例模式、观察者模式demo

    在Java中,实现单例模式有多种方式,如懒汉式(线程不安全)、饿汉式(静态常量)、双重检查锁定(DCL)等。其中,`Singleton.java`通常表示使用DCL实现的单例,它既保证了线程安全,又避免了不必要的同步开销。 ``...

    设计模式 中的 单例模式和观察者模式

    在Java中,可以使用双重检查锁定(Double-Check Locking)来实现线程安全的单例: ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static ...

    设计模式——单例模式(懒汉模式)

    总的来说,单例模式是一种常见的设计模式,懒汉式单例模式则是其中一种实现策略,它的主要特点是延迟加载和线程安全。在选择单例模式实现时,开发者需要根据具体需求考虑性能、线程安全以及代码简洁性等因素。

    Java并发编程(18)第五篇中volatile意外问题的

    但是,volatile并不保证原子性,这意味着如果一个变量的读写操作是复合的,比如i++,那么volatile并不能保证这个操作的线程安全。 在文档中,作者可能通过一个示例代码展示了volatile无法解决的并发问题,比如一个...

    面试官的一道简单的单例模式问题给我问懵了,详解单例模式双重检查加锁为什么要加volatile关键字!

    总结来说,`volatile`关键字在双重检查加锁的单例模式中至关重要,它保证了线程之间的可见性和禁止指令重排,使得在多线程环境下的单例初始化过程是线程安全的。如果没有`volatile`,即使使用了同步(如`...

    volatile学习手册

    在实际编程中,volatile常用于单例模式的双重检查锁定(DCL)、发布静态初始化字段、线程中断标志等场景,以保证线程间的数据同步和正确性。 总结,volatile是Java并发编程中不可或缺的一部分,它提供了一种相对轻...

    C#面向对象设计模式纵横谈-1.Singleton 单件(创建型模式)

    双检锁模式结合了两者优点,既保证了线程安全,又延迟了初始化,代码如下: ```csharp public sealed class Singleton { private static volatile Singleton instance; private static object syncRoot = new ...

    设计模式——单例模式

    **设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...

Global site tag (gtag.js) - Google Analytics