- 浏览: 198344 次
- 性别:
- 来自: 上海
文章分类
最新评论
前面几节介绍的模式涵盖了大部分的基本用例,在这些模式中使用 volatile 非常有用并且简单。这一节将介绍一种更加高级的模式,在该模式中,volatile 将提供性能或可伸缩性优势。
volatile 应用的的高级模式非常脆弱。因此,必须对假设的条件仔细证明,并且这些模式被严格地封装了起来,因为即使非常小的更改也会损坏您的代码!同样,使用更高级的 volatile 用例的原因是它能够提升性能,确保在开始应用高级模式之前,真正确定需要实现这种性能获益。需要对这些模式进行权衡,放弃可读性或可维护性来换取可能的性能收益 —— 如果您不需要提升性能(或者不能够通过一个严格的测试程序证明您需要它),那么这很可能是一次糟糕的交易,因为您很可能会得不偿失,换来的东西要比放弃的东西价值更低。
模式 #5:开销较低的读-写锁策略
目前为止,您应该了解了 volatile 的功能还不足以实现计数器。因为 ++x 实际上是三种操作(读、添加、存储)的简单组合,如果多个线程凑巧试图同时对 volatile 计数器执行增量操作,那么它的更新值有可能会丢失。
然而,如果读操作远远超过写操作,您可以结合使用内部锁和 volatile 变量来减少公共代码路径的开销。清单 6 中显示的线程安全的计数器使用 synchronized 确保增量操作是原子的,并使用 volatile 保证当前结果的可见性。如果更新不频繁的话,该方法可实现更好的性能,因为读路径的开销仅仅涉及 volatile 读操作,这通常要优于一个无竞争的锁获取的开销。
清单 6. 结合使用 volatile 和 synchronized 实现 “开销较低的读-写锁”
之所以将这种技术称之为 “开销较低的读-写锁” 是因为您使用了不同的同步机制进行读写操作。因为本例中的写操作违反了使用 volatile 的第一个条件,因此不能使用 volatile 安全地实现计数器 —— 您必须使用锁。然而,您可以在读操作中使用 volatile 确保当前值的可见性,因此可以使用锁进行所有变化的操作,使用 volatile 进行只读操作。其中,锁一次只允许一个线程访问值,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 保证读代码路径时,要比使用锁执行全部代码路径获得更高的共享度 —— 就像读-写操作一样。然而,要随时牢记这种模式的弱点:如果超越了该模式的最基本应用,结合这两个竞争的同步机制将变得非常困难。
发表评论
-
Java 5 并发学习(转)
2012-06-26 14:38 863Java 5 并发学习 在Java5之后,并发线程这块发生 ... -
WeakHashMap和HashMap的区别
2012-02-24 13:42 845http://mzlly999.iteye.com/blog/ ... -
The "Double-Checked Locking is Broken" Declaration
2012-02-22 10:34 960http://www.cs.umd.edu/~pugh/jav ... -
Log4j配置文件详细说明[转]
2012-02-14 10:48 1346属性文件Properties properties属性文件 ... -
Log4j的配置文件
2012-02-14 10:42 817Log4j支持两种配置文件格式,一种是java属性文件(键—值 ... -
单例模式的俩种方式
2012-01-04 14:09 937等等 单例模式的俩种方式: 饿汉式 class Singlet ... -
Mysql连接数据库:PreparedStatement.addBatch()方法
2011-12-23 08:43 58211.Eclipse连接MySQL数据库 mysql>C ... -
java中ArrayList 、LinkList区别
2011-12-21 15:30 1172java中ArrayList 、LinkList、List区别 ... -
Thread的实现
2011-12-21 14:25 1206Making a Thread A thread in Jav ... -
Date4j,一个简约的日期处理类库
2011-12-14 10:13 848Java本身的日期类在JDK1.0版本之后就再也没有更新过,同 ... -
How to use Log4j
2011-09-29 13:57 8121. LogManager.getInstance().get ... -
重写hashCode和equals方法(转)
2011-09-27 09:58 1136如果你的对象想散列存 ... -
学习Enum转
2011-09-22 14:11 8751. 关于 Java Enum: 学过 C/C++ 等 ... -
PO BO VO DTO POJO DAO概念及其作用(转)
2011-09-20 09:49 665J2EE开发中大量的专业缩略语很是让人迷惑,尤其是跟一些高手讨 ... -
Thread的实现
2011-09-20 09:47 859Thread的实现 1.extend Thread,then ... -
Adapter模式(转)
2011-08-17 15:48 890[b]GOF《设计模式》一书对Adapter模式是这样描述的: ... -
JVM常见配置汇总
2011-08-15 14:56 1904从这个图中可以看到, ... -
Abstract or Interface
2011-08-11 15:02 729详解java中的抽象类和接 ... -
HashMap HashTable TreeMap
2011-08-11 13:45 966Map中我们通过对象来对对象进行索引,用来索引的对象叫做key ... -
多线程死锁问题(转)
2011-08-10 19:42 586前天俺们谈到了加锁,但是在使用加锁的同时又会带来一个问题,就是 ...
相关推荐
在 `release` 模式下,如果没有使用 `volatile`,第二次读取 `i` 的值时可能不会从内存中重新读取,而是使用之前缓存的值。但使用了 `volatile` 后,每次访问 `i` 都会从内存中重新读取,确保获取的是最新值。 ####...
2. **单例模式中的双重检查锁定**:在实现线程安全的单例模式时,`volatile`关键字可以用来保证实例创建过程中的可见性和有序性,避免多线程环境下可能出现的问题。 3. **懒汉式初始化**:在某些情况下,为了避免...
`volatile`的高级用法 #### (3.1) 确保可见性 当多个线程访问同一个变量时,为了保证数据的一致性和可见性,可以使用`volatile`关键字。例如,在多线程环境中,如果一个线程修改了一个变量,而另一个线程需要读取...
例如,作为共享状态的标志,用于多线程间的通信,例如单例模式的双重检查锁定(Double-Check Locking)中,volatile可以确保线程安全地初始化单例。 5. **原理**:在底层实现上,volatile变量在汇编代码中会包含一...
DCL模式结合了两者优点,既保证了线程安全,又实现了延迟初始化。 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,当创建对象时,我们不会对客户端暴露创建逻辑,而是提供一个接口...
3. 简单计数器:如果计数器的增加操作是线程安全的(例如,仅包含读和写操作),可以使用`volatile`来实现简单的计数器。 需要注意的是,虽然`volatile`提供了轻量级的同步机制,但在设计多线程程序时,应优先考虑...
### 线程安全的单例模式详解 #### 一、单例模式简介 单例模式(Singleton Pattern)是软件开发中最常用的创建型设计模式之一,它的主要目标是确保一个类只有一个实例,并提供一个全局访问点。单例模式在很多场景下...
Java volatile的适用场景实例详解 Java volatile 关键字是 Java 并发编程中的一种...volatile 变量是一种非常有用的线程安全机制,但是它的使用需要非常小心,需要遵守一定的使用条件和模式,以避免出现线程安全问题。
设计模式概述与 Singleton 模式详解 在软件设计中,设计模式是解决问题的方案,学习现有的设计模式可以做到经验复用。拥有设计模式词汇,在沟通时就能用更少的词汇来讨论,并且不需要了解底层细节。 设计模式可以...
- 单例模式中的双重检查锁定(Double-Check Locking),确保实例化过程线程安全。 - 标记共享状态,比如在标志变量中,表示某个条件是否满足,如`isRunning`。 - 并发量小、更新频率低的共享计数器,如访问次数...
饿汉模式是在类加载时就完成了初始化,因此类加载比较慢,但获取单例对象的速度快,且线程安全。由于实例在类加载时已经创建,所以不会出现多线程下的并发问题。饿汉模式的实现代码通常如下: ```java public class...
在实际应用中,volatile常用于简单的状态标记,如标志位(例如:一个线程是否应该继续运行),或者是单例模式中的Double-Check Locking(双重检查锁定)中用来确保实例化过程的正确性。不过,需要注意的是,过度依赖...
在Java中,实现单例模式有多种方式,如懒汉式(线程不安全)、饿汉式(静态常量)、双重检查锁定(DCL)等。其中,`Singleton.java`通常表示使用DCL实现的单例,它既保证了线程安全,又避免了不必要的同步开销。 ``...
在Java中,可以使用双重检查锁定(Double-Check Locking)来实现线程安全的单例: ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static ...
总的来说,单例模式是一种常见的设计模式,懒汉式单例模式则是其中一种实现策略,它的主要特点是延迟加载和线程安全。在选择单例模式实现时,开发者需要根据具体需求考虑性能、线程安全以及代码简洁性等因素。
但是,volatile并不保证原子性,这意味着如果一个变量的读写操作是复合的,比如i++,那么volatile并不能保证这个操作的线程安全。 在文档中,作者可能通过一个示例代码展示了volatile无法解决的并发问题,比如一个...
总结来说,`volatile`关键字在双重检查加锁的单例模式中至关重要,它保证了线程之间的可见性和禁止指令重排,使得在多线程环境下的单例初始化过程是线程安全的。如果没有`volatile`,即使使用了同步(如`...
在实际编程中,volatile常用于单例模式的双重检查锁定(DCL)、发布静态初始化字段、线程中断标志等场景,以保证线程间的数据同步和正确性。 总结,volatile是Java并发编程中不可或缺的一部分,它提供了一种相对轻...
双检锁模式结合了两者优点,既保证了线程安全,又延迟了初始化,代码如下: ```csharp public sealed class Singleton { private static volatile Singleton instance; private static object syncRoot = new ...
**设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...