`
春花秋月何时了
  • 浏览: 42037 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

同步数据结构之原子类序章

 
阅读更多

概述

关于Java并发包的原子相关类其实可以在Unsafe后面紧接着进行介绍,因为这些原子类其实只是建立在对Unsafe的调用基础上并没有利用到Java并发包的其他类,出于前面介绍的同步组件在Java并发包的重要性,我才将它们放在了原子类的前面。

Java从JDK 1.5开始提供的java.util.concurrent.atomic原子包给开发人员提供了一组用法简单、性能高效、线程安全的更新单个变量的方法。并且相对于使用传统的synchronized关键字的方式,原子包从使用者层面上看,是一种更加轻量级、细粒度、无锁的保证线程安全的策略。

因为原子包其实采用的是CAS + Volatile关键字的方式实现的这些无锁高效的线程安全机制,而CAS机制实际上是直接借助了当前平台的CPU的相关高效的原子指令来完成的,而在某些平台的CPU架构上原子包在实现的时候在内部还是借助了某种形式的内部锁的思想,所以原子包中的那些看似无锁的线程安全的方法还是具有一定程度的平台相关性,在某些平台上不能绝对保证线程不被阻塞。

 

原子包中的类可以分为5类:

  1. 原子更新标量类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
  2. 原子更新数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
  3. 原子更新字段类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
  4. 原子更新复合类:AtomicMarkableReference,将一个布尔值与引用变量关联起来,可用于标记数据结构中的节点等;AtomicStampedReference,将一个整数值与引用变量关联起来,可用于添加更新版本号解决ABA问题
  5. JDK8新增的高竞争下的累加器及其扩展类:Striped64,LongAccumulator,LongAdder,DoubleAccumulator,DoubleAdder

原子包中的大部分类及其实现方法都包含或利用如下几个重要方法:

  1. get:由于操作的变量被volatile修饰,所以具有读取 volatile 变量的内存效果,总是能够获取到最新的值。
  2. set由于操作的变量被volatile修饰,所以具有写入volatile 变量的内存效果,立即将更新刷新到主存对其他线程可见。 
  3. lazySet即“延迟可见写”,直接使用的Unsafe的putOrderedXXX(Object o, long offset, long x)方法实现,该方法在Unsafe章节已经详细分析过,它能够执行高效的写入,但不保证更改立即对其他线程可见,而且由于在前面加上了store-store内存屏障,所以能够保证前面的写操作不会被重排序到lazySet的后面去。
  4. compareAndSet、getAndIncrement等读写方法compareAndSet是CAS机制的实现方法,保证了操作的原子性,当操作的变量是被volatile修饰的时候,它具备了volatile变量读写操作的内存效果,原子包中操作的属性都是被volatile修饰的,所以原子包中的CAS操作都具有读写volatile变量的内存效果,也就说同时满足了可见性、有序性以及原子性。除此之外,getAndIncrement等其他读写方法都具有相同的内存效果。
  5. weakCompareAndSet我们知道compareAndSet同时具有volatile变量的内存效果,确切是说,它除了能保证对自身变量的读写操作的原子性与有序性、可见性外,还能因为对volatile变量的写操作会在其前后加入相应的内存屏障达到使其前面的其他写和后面的读操作不但不能重排序而且还会跟着变得立即可见,也就是说compareAndSet + volatile同时保证了在该操作前后的其他读写操作的有序性和可见性,即它们满足happen-before规则。而原子包提供的该weakCompareAndSet方法则被称之为不保证有序性的compareAndSet方法,也就是说weakCompareAndSet只保证对自身操作的原子性和可见性,但不保证在该操作前面和后面的其他读写操作的有序性和可见性,即不附带任何的happen-before规则,更通俗的说就是,weakCompareAndSet只保证自身的原子性和可见性,在它前面和后面的其他读写操作可能会被重排序,所以当其他线程能够看到weakCompareAndSet操作的结果时,并不保证一定也能看到在weakCompareAndSet操作前面或者后面的操作的结果。一般来说,weakCompareAndSet都比compareAndSet更加高效,常常用于在程序运行时更新计数器或者统计数据这类无关于其他happens-before的程序中非常有用。另外,weakCompareAndSet操作可能会返回一个虚假的失败结果false,这种失败可能是由于内存冲突导致的,而和预期值(expectedValue)是否和当前的值相等无关。最后,通过查看原子包的源码,你会发现weakCompareAndSet和compareAndSet方法的实现是一模一样的,这是因为weakCompareAndSet是由JVM在运行时通过JIT即时编译的平台相关的手写汇编程序替换执行的,所以只有在运行时通过hsdis插件和JVM参数-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly打印出真正执行的汇编指令才会发现他们的差异(奇怪的是我在测试的时候,发现该测试程序需要循环多次调用才能看到相应的汇编指令)。值得一提的是,在JDK9中,(weak)compareAndSet这两个方法已经被加上了一个@HotSpotIntrinsicCandidate注解,更加明确的表示这两个方法可能( 但不保证 )通过HotSpot VM自己来写汇编或IR编译器来实现该方法以提供性能。

原子类主要被设计为用于实现非阻塞数据结构和相关基础结构类。compareAndSet方法也不是锁的常规替换方法,仅当对象的重要更新限定于单个变量时才使用它。

原子类也不是java.lang.Integer 和相关类的常规替换。原子类没有定义诸如 equals、hashCode 和 compareTo 之类的方法。(因为原子变量是期望可变的,所以对于哈希表的键值来说,它们不是好的选择。)另外,原子包仅为一些常用的类型提供了原子类。例如,并没有表示 byte 的原子类。如果要实现这种不常见类型的原子类,可以使用 AtomicInteger 来保存 byte 值,并进行适当的强制转换。也可以使用 Float.floatToRawIntBits(float) 和 Float.intBitsToFloat(int) 转换来保存 float 类型的值,使用 Double.doubleToRawLongBits(double) 和 Double.longBitsToDouble(long) 转换来保存 double 类型的值。

 

本章节从整体到局部重要方法的形式阐述了Java并发包的atomic原子类的设计思想以及原子类家族的5种成员结构,接下来的章节我将分别对这5种原子类进行分析研究。 

分享到:
评论

相关推荐

    数据结构同步练习册习题及答案

    ### 数据结构同步练习册习题及答案解析 #### 第1章 绪论 **1.1 学习指导** 在本章中,我们将探讨数据结构的基础知识,这为后续章节的学习奠定理论基础。 ##### 1.1.1 本章主要内容 1. **数据结构与抽象数据类型...

    原子指令于Lock-Free数据结构教学笔记

    ### 原子指令与Lock-Free数据结构 #### 原子指令概述 **原子指令**是一种特殊的硬件指令,能够以不可分割的方式对一个或多个内存位置执行操作。这意味着无论其他处理器正在执行何种指令,原子操作要么全部成功,...

    原子类测试

    - `AtomicReference`:存储对象引用的原子操作,可以实现无锁的数据结构。 2. 数组版本的原子类: - `AtomicIntegerArray`、`AtomicLongArray`和`AtomicReferenceArray`:分别对应整型、长整型和引用类型的数组,...

    学生基本信息管理 数据结构

    在IT行业中,数据结构是计算机科学的基础之一,它关乎如何高效地存储和处理数据。在这个“学生基本信息管理 数据结构”项目中,我们将会探讨如何利用数据结构和C++编程语言来设计一个系统,用于管理学生的基本信息。...

    一种采用Lock-Free同步机制的数据结构的研究.pdf

    本文提出了一种针对跳表(Skip list)共享数据结构的无锁(Lock-Free)同步机制方法,并对其线性一致性(linear consistency)进行了证明。在嵌入式系统中,混合关键任务的共享优先级调度队列(shared priority ...

    并发数据结构(Concurrent data structures)

    这些系统能够并行执行多个计算线程,并通过共享内存中的数据结构进行通信和同步。数据结构的效率直接影响到系统的整体性能。 然而,设计适用于多处理器环境的有效数据结构是一项极具挑战性的任务。相比传统的顺序...

    Lock free 论文集合,若干无锁数据结构实现的经典论文,500多页.zip

    Java提供了java.util.concurrent.atomic包,包含各种原子类,如AtomicInteger、AtomicReference等,方便开发者构建无锁数据结构。Python虽然没有内置的无锁原语,但可以通过使用Cython或者第三方库如threading....

    基于饿汉模式的并发数据结构设计.pptx

    例如,可以通过硬件指令如CAS(Compare-And-Swap)来实现原子操作的支持,也可以利用Java等高级语言提供的原子类或关键字来简化原子操作的使用。 2. **锁**:锁是另一种常用的并发控制机制。其中,互斥锁允许一个...

    算法与数据结构 分布式算法课程 第02章 分布式算法简介 共59页.pdf

    在“算法与数据结构:分布式算法课程”的第二章中,主要介绍了分布式算法的基本概念及其重要性。本章节内容涉及分布式系统的建模方法、分布式系统中的定时机制、进程间通信方式以及不同类型的故障处理等关键知识点。...

    Java concurrency之AtomicLongArray原子类_动力节点Java学院整理

    Java并发编程中的`AtomicLongArray`是`java.util.concurrent.atomic`包中的一种数据结构,它提供了一种原子性地操作长整型数组的方式。这个类主要用于在多线程环境中实现高效且线程安全的数组元素更新。下面我们将...

    《Java语言程序设计(进阶篇)》 课后习题第25章代码chapter25.rar

    10. **Java并发编程**:深入理解并发容器,如`ConcurrentHashMap`, `ConcurrentLinkedQueue`等,以及原子类`AtomicInteger`, `AtomicReference`等。 通过解决这些习题,学生不仅可以巩固已学的Java基础知识,还能...

    三辆小车同步

    在实际编程中,还需要考虑到线程安全的数据结构、异常处理和资源管理等问题,以保证程序的健壮性和性能。同时,测试和调试也是关键步骤,确保在各种情况下,三辆小车都能正确同步移动。 总的来说,"三辆小车同步"是...

    java多线程中的原子操作

    在Java中,`java.util.concurrent.atomic`包提供了多种原子类,如AtomicInteger、AtomicLong等,这些类支持原子性的增加、减小、更新等操作,避免了显式的同步锁的使用,提高了并发性能。例如,AtomicInteger的...

    JAVA数据结构

    通过对上述知识点的学习,我们不难发现数据结构作为计算机科学领域的基石之一,在实际项目开发过程中扮演着极其重要的角色。无论是基础知识还是高级技巧,都需要不断积累和实践才能达到熟练运用的水平。希望每位JAVA...

    Programming with POSIX threads 第三章线程同步

    例如,互斥量和条件变量通常用于保护复杂的数据结构,而信号量则适用于管理资源池。了解这些工具的优缺点以及如何正确使用它们是编写高效、可靠的多线程程序的关键。 理解并熟练掌握pthreads库的同步机制对于在...

    可重复使用的并行数据结构和算法.pdf

    《可重复使用的并行数据结构和算法》这篇文章探讨了在并行编程中常见的9种数据结构和算法,这些工具对于优化多线程和并发程序的性能至关重要。以下是这些数据结构和算法的详细介绍: 1. 倒计数锁存(Countdown Latch...

    高性能并行计算中的同步策略.pptx

    2. **无锁数据结构**:基于原子操作或其他低级同步机制构建的数据结构,能够在没有锁的情况下实现线程安全。例如,无锁队列和无锁哈希表等。 ##### 基于事务内存的同步机制 1. **乐观并发控制 (OCC)**:假设事务...

    与NTP服务器时间同步的类

    `VxDType.h`可能是包含通用数据类型的头文件,如网络数据包结构或错误代码定义。 NTP通信的基本步骤通常包括: 1. **发送请求**:客户端向NTP服务器发送一个请求报文,该报文包含客户端的当前时间戳。 2. **接收...

Global site tag (gtag.js) - Google Analytics