`

volatile原理与并发cas

    博客分类:
  • java
阅读更多

 为什么使用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多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    Java 多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池) Java 多线程是 Java 语言中的一种并发编程机制,允许程序同时执行多个线程,以提高程序的执行效率和响应速度。 Java 多线程机制提供了...

    JUC最详细思维导图,一次了解读写锁,可重入锁,Cas原理,volatile 关键字原理

    本文将深入探讨其中的关键概念,包括读写锁、可重入锁、CAS原理以及volatile关键字。 首先,我们来看读写锁。读写锁允许多个线程同时进行读操作,但在写操作时,只有一个线程能够获得锁。这种设计极大地提高了并发...

    Java并发机制的底层实现原理.pdf

    Java并发机制的底层实现原理涉及到多个方面,包括了本地内存与线程安全的问题、volatile关键字的使用、synchronized关键字的原理以及Java并发在处理器层面是如何实现的。通过这些机制,Java能够有效地管理多线程环境...

    synchronized ReentrantLock volatile Atomic 原理分析.docx

    本文将深入探讨四种关键的并发控制机制:synchronized关键字、ReentrantLock(可重入锁)、volatile关键字以及Atomic类的原理与应用。 ### 1. synchronized关键字 `synchronized`关键字是Java提供的内置锁,用于...

    深入分析Java并发编程之CAS

    首先,CAS操作的原理是:在执行更新操作前,先比较当前变量的值是否与预期值相等,如果相等则更新,否则不做任何操作。这种乐观锁策略假设并发冲突较少,可以减少锁带来的同步开销。在Java中,CAS操作是通过`Unsafe`...

    JUC包含线程,线程池,CAS,volatile等底层原理,以及相关问题的解决方式以及相关工具类的使用

    JUC包括线程、线程池、CAS(Compare and Swap)操作、volatile关键字以及其他相关的底层原理和解决方案。 **synchronized底层原理** synchronized是Java中的内置锁,它在字节码层面表现为monitorenter和monitorexit...

    并发容器的原理,7大并发容器详解、及使用场景

    这些容器通常使用更精细的锁策略,如分段锁(Segment)、CAS(Compare and Swap)算法,以及 volatile 关键字,以提高并发性并减少锁冲突。 1. ConcurrentHashMap 是并发容器中的重要成员,它是 HashMap 的并发版本...

    java并发编程与实践

    6. **原子操作与CAS**:Atomic类提供了一种无锁编程的方式,利用硬件级别的比较并交换(Compare and Swap, CAS)操作实现原子性更新,以提高并发性能。 7. **线程池设计**:线程池可以有效管理并发线程,避免频繁...

    java并发编程实战源码,java并发编程实战pdf,Java

    6. **原子操作与CAS**:AtomicInteger、AtomicLong等原子类利用了硬件级别的CAS(Compare and Swap)操作,实现了无锁编程,提高了并发性能。 7. **死锁、活锁与饥饿**:并发编程中常见的问题,需要理解和避免这些...

    Java 多线程与并发(8-26)-JUC原子类- CAS, Unsafe和原子类详解.pdf

    Java多线程与并发处理是Java编程中的高级话题,涉及到JUC(java.util.concurrent)包中的原子类、CAS(Compare-And-Swap)机制、Unsafe类以及多线程并发的无锁方案和线程安全的实现方法。 CAS是一种无锁的同步机制...

    Java并发编程设计原则与模式.pdf

    7. **原子操作与CAS**:Atomic类和CompareAndSwap(CAS)操作是Java并发编程中的无锁技术,用于实现高效且线程安全的数据更新。书中讲解了如何利用这些机制来实现无锁数据结构。 8. **延迟初始化与单例模式**:书中...

    Java并发编程与高并发解决方案笔记-基础篇.docx

    JMM通过内存屏障和volatile、synchronized关键字来保证并发编程的安全性。 5. **并发的优势与风险** - **优势**:并发能提高系统资源利用率,提升程序响应速度,特别是在多核环境下,可以显著提高性能。 - **风险...

    Java并发编程面试题

    在Java程序中,多线程的运行安全可以通过使用synchronized关键字、Lock类、volatile关键字、CAS操作等实现。同时,Java也提供了线程池、Executor框架等机制来管理线程的创建和执行。 下面是Java并发编程面试题的...

    01-并发编程之深入理解JMM&并发三大特性(一).pdf

    在学习过程中,除了关注并发三大特性,还需要掌握volatile、synchronized、Lock和CAS等关键字和工具的使用,这些都是实现线程安全的基础。如果对计算机组成原理和操作系统知识感兴趣,可以通过相关课程进行系统性...

    JUC并发编程与源码分析视频课.zip

    在本课程中,你将学习到如何利用这些工具来提升应用程序的并发性能,同时理解其底层实现原理。 课程内容可能涵盖以下几个核心知识点: 1. **线程与并发基础**:首先,会介绍Java中的线程概念,包括线程的创建、...

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

    8. **原子操作与CAS**:Java的`Atomic`类提供了一种无锁编程的方式,基于Compare and Swap(CAS)操作实现原子性更新。书中会讲解原子操作的原理和应用场景。 9. **Future和Callable**:`Future`接口和`Callable`...

    java并发编程库

    软件层面上,J.U.C的许多设计思想与现代编程语言中的并发模型相呼应,例如函数式编程和响应式编程中的一些概念。J.U.C的设计者们利用这些理论知识,为Java开发者提供了一套成熟的并发编程解决方案。 当然,J.U.C库...

    多线程与高并发-电子.pdf

    多线程与高并发是计算机科学中非常重要的两个概念,它们在提高软件程序的性能、响应速度和资源利用率方面起着至关重要的作用。在当今的互联网时代,特别是在产业互联网和5G技术的推动下,多线程和高并发的应用变得...

    java高并发编程第一版

    8. **原子操作与CAS**:Atomic类和Compare-and-Swap(CAS)算法是无锁编程的基础,通过非阻塞的方式实现线程间的协调,可以提高并发程序的效率。 9. **Java并发库的最新发展**:如果书籍更新至较新版本,可能会包含...

Global site tag (gtag.js) - Google Analytics