`
lenovo123
  • 浏览: 11367 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

转:volatile的原理与技巧

    博客分类:
  • JAVA
阅读更多

转自:http://www.builder.com.cn/2007/1107/612888.shtml

 

volatile, 用更低的代价替代同步

为什么 使用volatile比同步代价更低?
同步的代价, 主要由其覆盖范围决定, 如果可以降低同步的覆盖范围, 则可以大幅提升程序性能. 

而volatile的覆盖范围仅仅变量级别的. 因此它的同步代价很低.

volatile原理是什么?
volatile的语义, 其实是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我.(工作内存详见java内存模型)

因此, 当多核或多线程在访问该变量时, 都将直接
操作 主存, 这从本质上, 做到了变量共享.

volatile的有什么优势?
1, 更大的程序吞吐量
2, 更少的代码实现多线程
3, 程序的伸缩性较好
4, 比较好理解, 无需太高的学习成本

volatile有什么劣势?
1, 容易出问题
2, 比较难设计

 

volatile运算存在脏数据问题

volatile仅仅能保证变量可见性, 无法保证原子性.

volatile的race condition示例:

public class TestRaceCondition {
    private volatile int i = 0;
   
    public void increase() {
       i++;
    }

    public int getValue() {
       return i;
    }
}

当多线程执行increase方法时, 是否能保证它的值会是线性递增的呢?
答案是否定的.

原因:
这里的increase方法, 执行的操作是i++, 即 i = i + 1;
针对i = i + 1, 在多线程中的运算, 本身需要改变i的值.
如果, 在i已从内存中取到最新值, 但未与1进行运算, 此时其他线程已数次将运算结果赋值给i.
则当前线程结束时, 之前的数次运算结果都将被覆盖.

即, 执行100次increase, 可能结果是 < 100.
一般来说, 这种情况需要较高的压力与并发情况下, 才会出现.

如何避免这种情况?
解决以上问题的方法:
一种是 操作时, 加上同步.
这种方法, 无疑将大大降低程序性能, 且违背了volatile的初衷.

第二种方式是, 使用硬件原语(CAS), 实现非阻塞算法
从CPU原语上,  支持变量级别的低开销同步.

 

CPU原语-比较并交换(CompareAndSet),实现非阻塞算法

什么是CAS?
cas是现代CPU提供给并发程序使用的原语操作. 不同的CPU有不同的使用规范.

在 Intel 处理器中,比较并交换通过指令的 cmpxchg 系列实现。
PowerPC 处理器有一对名为“加载并保留”和“条件存储”的指令,它们实现相同的目地;
MIPS 与 PowerPC 处理器相似,除了第一个指令称为“加载链接”。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)

什么是非阻塞算法?
一个线程的失败或挂起不应该影响其他线程的失败或挂起.这类算法称之为非阻塞(nonblocking)算法

对比阻塞算法:
如果有一类并发操作, 其中一个线程优先得到对象监视器的锁, 当其他线程到达同步边界时, 就会被阻塞.
直到前一个线程释放掉锁后, 才可以继续竞争对象锁.(当然,这里的竞争也可是公平的, 按先来后到的次序)

CAS 原理:

我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

CAS使用示例(jdk 1.5 并发包 AtomicInteger类分析:)

    /**
     * Atomically sets to the given value and returns the old value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

这个方法是, AtomicInteger类的常用方法, 作用是, 将变量设置为指定值, 并返回设置前的值.
它利用了cpu原语compareAndSet来保障值的唯一性.

另, AtomicInteger类中, 其他的实用方法, 也是基于同样的实现方式.
比如 getAndIncrement, getAndDecrement, getAndAdd等等.

CAS语义上存在的 "
ABA 问题"

什么是ABA问题?
假设, 第一次读取V地址的A值, 然后通过CAS来判断V地址的值是否仍旧为A, 如果是, 就将B的值写入V地址,覆盖A值.

但是, 语义上, 有一个漏洞, 当第一次读取V的A值, 此时, 内存V的值变为B值, 然后在未执行CAS前, 又变回了A值.
此时, CAS再执行时, 会判断其正确的, 并进行赋值.

这种判断值的方式来断定内存是否被修改过, 针对某些问题, 是不适用的.

为了解决这种问题, jdk 1.5并发包提供了AtomicStampedReference (有标记的原子引用)类, 通过控制变量值的版本来保证CAS正确性.

其实, 大部分通过值的变化来CAS, 已经够用了.




jdk1.5原子包介绍(基于volatile)

包的特色:
1, 普通原子数值类型AtomicInteger, AtomicLong提供一些原子操作的加减运算.

2, 使用了解决脏数据问题的经典模式-"比对后设定", 即 查看主存中数据是否与预期提供的值一致,如果一致,才更新.

3, 使用AtomicReference可以实现对所有对象的原子引用及赋值.包括Double与Float,
但不包括对其的计算.浮点的计算,只能依靠同步关键字或Lock接口来实现了.

4, 对数组元素里的对象,符合以上特点的, 也可采用原子操作.包里提供了一些数组原子操作类
AtomicIntegerArray, AtomicLongArray等等.

5, 大幅度提升系统吞吐量及性能.

具体使用, 详解java doc.

分享到:
评论

相关推荐

    深入JVM内核—原理、诊断与优化

    《深入JVM内核—原理、诊断与优化》是一份深度探索Java虚拟机(JVM)的视频教程,旨在帮助开发者全面理解JVM的工作机制,掌握性能诊断技巧,并能进行有效的优化。本教程覆盖了从基础到高级的JVM主题,不仅适用于Java...

    VLSI-Design of Non-Volatile Memories

    - **NOR Flash 的设计与实现**:特别关注了NOR Flash的设计方法、制造工艺和性能优化技巧。 - **案例研究**:提供了多个实际应用案例,帮助读者更好地理解理论知识如何转化为具体的产品开发过程。 **适合读者群:**...

    java面试技巧及笔试汇集

    4. 线程安全:了解并发编程中的volatile、Atomic类和ThreadLocal。 六、网络编程 1. Socket通信:理解TCP和UDP协议,以及Socket和ServerSocket类的使用。 2. HTTP协议:了解HTTP的基本原理,能实现简单的HTTP客户端...

    程序员的面试模板及技巧资料.pdf,这是一份不错的文件

    - **垃圾回收(GC)**: 了解不同类型的GC(Minor GC, Full GC, CMS, G1等),GC的工作原理,以及如何优化内存管理。 - **JVM内存模型**: 包括堆内存、栈内存、方法区、本地方法栈等区域的用途和大小调整。 3. **...

    精通并发与netty 无加密视频

    第83讲:AtomicIntegerFieldUpdater实例演练与volatile关键字分析 第84讲:Netty引用计数注意事项与内存泄露检测方式 第85讲:Netty编解码器剖析与入站出站处理器详解 第86讲:Netty自定义编解码器与TCP粘包拆包...

    Java并发编程:设计原则与模式(第二版).rar

    书中会详细讲解这些集合类的设计原理和使用技巧。 5. **并发设计模式**:书中涵盖了多种经典的并发设计模式,如生产者消费者模式、读写锁模式、双检锁/双重校验锁模式(DCL)等,帮助读者理解如何在实际项目中应用...

    JAVA面试技巧与试题大全

    首先,我们来探讨Java面试中的技巧: 1. **自我介绍**:简洁明了地介绍自己的教育背景、工作经验和项目经验,强调与Java相关的技能和成就。 2. **基础知识**:熟练掌握Java的基础语法,如类、对象、封装、继承、...

    java技术储备,如何提升自己

    3. volatile:深入理解 volatile 关键字的作用和实现机制。 4. CAS:了解 CAS(Compare And Swap)的实现机制和应用场景。 5. JUC 工具类:了解 JUC 工具类的使用和实现机制。 6. 锁机制:了解 Java 锁的底层实现,...

    亚嵌培训资料linux c语言一站式学习

    ### 亚嵌培训资料:Linux C语言一站式学习 ...通过系统地学习上述知识点,学员能够全面掌握Linux环境下C语言的编程技巧,深入理解计算机底层运作原理,为后续更高级别的软件开发与系统优化打下坚实的基础。

    诺瓦科技2021嵌入式软件_嵌入式-常用知识&面试题库_大厂面试真题.docx

    1. volatile 使用原理:了解volatile关键字的使用原理和应用场景,包括volatile变量的使用和实现方法。 2. 项目管理:了解项目管理的基本概念和方法,包括需求分析、设计、实现和测试等。 诺瓦科技2021嵌入式软件...

    深入JVM内核 - 原理、诊断与优化

    在本课程中个,将详细介绍JVM的基本原理、组成以及工作方式,并配合实际案例,介绍相关的调优技巧。 课程大纲: 第一课 初识JVM JVM分类 Java语言规范 JVM规范 介绍JVM的基本知识和发展历史,并介绍了Java语言...

    Java程序设计技巧与开发实例

    《Java程序设计技巧与开发实例》是一本专为Java初学者和进阶开发者设计的教程,旨在通过丰富的实例深入解析Java编程的核心技术和实践方法。在Java这个强大的面向对象编程语言中,掌握有效的设计技巧和实践经验对于...

    Java常见面试题及解析电子书&Java;程序员面试技巧

    以下是一些关键技巧: 1. **基础知识牢固**:理解并掌握Java的基础概念,如类、对象、封装、继承、多态等,以及JVM的工作原理。 2. **数据结构与算法**:熟悉常见的数据结构(如数组、链表、栈、队列、树、图)和...

    Linux一站式学习

    - **volatile限定符**: volatile关键字的用途和意义。 **20. 链接详解** - **多目标文件的链接**: 多个目标文件链接成可执行文件的过程。 - **定义和声明** - **extern和static关键字**: extern和static的作用域及...

    Java面试题大全.docx

    - volatile关键字的作用及原理。 9. **Spring框架**: - Spring的核心组件:IoC(控制反转)、AOP(面向切面编程)。 - Bean的生命周期管理,依赖注入(DI)。 - Spring MVC:控制器、模型、视图的交互。 10. ...

    【Java面试资料】-(机构内训资料)上海-拼多多-Java高级

    - ORM框架:MyBatis、Hibernate的工作原理及使用技巧。 这份资料全面覆盖了Java高级开发所需的知识点,对于希望在上海拼多多或其他公司从事Java开发的求职者来说,是一份宝贵的复习资源。通过深入学习和理解这些...

    C++ Builder 5编程实例与技巧.02

    ### C++ Builder 5编程实例与技巧:C++关键技术概览 #### 一、C++ Builder集成开发环境 C++ Builder 5是一款功能强大的集成开发环境(IDE),它旨在简化Windows环境下C++语言的编程过程。通过使用C++ Builder 5,...

    java面试宝典,包含java基础篇、多线程、spring、springboot、mysql、redis、mq等等经典面试问题

    Java面试宝典是一份全面覆盖Java相关技术领域的面试指南,旨在帮助求职者准备技术面试,提升面试成功率。这份资源包含了Java基础...通过阅读和学习这些内容,不仅可以提高面试技巧,还能提升实际工作中的问题解决能力。

    Java底层知识点、源码解读,技术栈相关原理知识点、工具解读最佳实践、功能点实战,问题排查,开发技巧等

    5. **并发与多线程**: Java提供了丰富的并发编程工具,如synchronized、volatile、Lock接口、Future、CompletableFuture等。理解并发原理和线程池的使用是提升程序效率的关键。 6. **异常处理**: 学习如何正确使用...

    互联网高频Java后端面试题20道(适合1~3年)V1.0.84.docx

    解析:理解 JVM 的工作原理对于优化 Java 应用的性能和解决内存问题至关重要。开发者可以通过调整 JVM 参数来改善程序的运行效率。 问题 8:请解释 Java 中的异常处理机制,并给出 try-catch-finally 语句块的作用...

Global site tag (gtag.js) - Google Analytics