章节介绍

主要包括 术语定义、处理器如何实现原子操作、Java如何实现原子操作;

原子(atomic)本意是 不能再进一步分割的最小粒子,“原子操作” 意为 不可被中断的一个或一系列操作。

术语定义

自己的理解:

  缓存行:缓存的最小操作单位。注意,缓存与内存是不一样的。

  比较并交换:结合上一篇中CAS操作的介绍进行理解。CAS操作需要输入两个数值,一个新值A,一个旧值B,在操作期间先比较旧值B有没有发生变化,没有发生变化,才交换,发生了变化,就不交换。

  CPU流水线:结合生产车间的流水线,一种设备或者工人只做一个工作,等这几个设备或者工人都工作了一遍,也就是完成了一个CPU的时钟周期。

  内存顺序冲突:这一般是指多个CPU同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效,当出现这个内存顺序冲突时,CPU必须清空流水线。

处理器如何实现原子操作

  (1)使用总线锁保证原子性

    如果多个处理器同时对共享变量进行改写操作(经典例子 i++),那么共享变量就会被多个处理器同时进行操作,这样读改写操作就不是原子的,操作完之后共享变量的值会和期望的不一样。以 i++ 为例,如果我们进行两次i++操作,我们期望的值是3,但是可能是2。原因可能是 多个处理器同时从各自的缓存中读取变量,分别进行了加 1 操作,然后分别写入到系统内存中。

  那么,想要保证读改写共享变量时候的操作时原子的,就必须保证在一个处理器读改写共享变量的时候,其他处理器不能操作缓存了该共享变量内存地址的缓存。处理器使用总线索来解决这个问题。总线索 就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出该信号时,其他处理器的请求就处于阻塞,该处理器可以独占共享内存。

  (2)使用缓存锁保证原子性  

    在同一个时刻,我们只需要保证对某个内存地址的操作是原子性即可,但总线锁定把CPU和内存之间的通信锁定了,这样造成的后果就是,在总线锁定期间,其他处理器不能操作其他内存地址的数据,所以总线锁定的开销比较大。

    频繁使用的内存会缓存在处理器的L1、L2、L3的高速缓存里,那么原子操作就可以直接在内部缓存中进行,并不需要声明总线锁。

    缓存锁定:如果内存区域被缓存到处理器的缓存行中,并且在LOCK操作期间被锁定,那么当它执行锁操作回写到内存时,处理器不在总线上声言LOCK#信号,而是修改内部分存储地址,并允许他的缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据,当其他处理器回写已被锁定的缓存行的数据时,会使缓存行无效。以 多个处理器 执行 i++为例,如果CPU1修改缓存行中的i时使用了缓存锁定,那么CPU2等就不能同时缓存 i 的缓存行。

    关键字:为例保证各个处理器的缓存一致、缓存一致性协议、每个处理器、嗅探、总线、数据、检查、过期、无效状态、内存、重新读取

    备注:可以结合 volatile的实现原则进行理解学习。

    特殊情况,不能使用缓存锁定:(1)当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行,则处理器会调用总线锁定;

                  (2)有些处理器不支持缓存锁定。

Java如何实现原子操作?

  在Java中可以通过  锁 和 循环CAS的方式来实现。

  (1)使用循环CAS操作实现原子操作。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止,举例:实现一个基于CAS线程安全的计数器方法。

    从Java1.5开始,JDK的并发包里提供了一些类用于支持原子操作,如 AtomicBoolean(用原子的方式更新boolean值)、Atomicinteger(用原子的方式更新int值)和AtomicLong(用原子方式更新long值)。这些包装类中还提供了有用的工具方法,比如 以原子的方式将当前值自增1 和 自减1。

  (2)CAS实现原子操作的问题

    ABA问题;循环时间长开销大;只能保证一个共享变量的原子操作。

    ABA问题说明:在CAS操作 值的时候,会检查值有没有发生变化。如果一个值原来是A,变成了B,又变成了A,这样的话,用CAS检查时候,会发现他的值没有变化,实际上却发生变化了。解决思路就是 使用版本号。每次变化,都会更新版本号:1A-->2B-->3A。

    从Java1.5开始,JDK的Atomic包里提供了一个类 AtomicStampedReference 来解决ABA问题。这个类的 compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志。如果都相等,则把该引用 和该标志的值都更新为给定的值。

    自旋CAS如果长时间不能成功,会给CPU带来非常大的执行开销。如果JVm能够支持处理器提供的pause命令,那么效率会有一定的提升。

    对一个共享变量执行操作时候,我们可以循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性了,这是就得使用 锁。取巧的方式:多个共享变量合并成一个共享变量来操作。举例:i = 2; j = a ,合并为 ij = 2a。

    从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。(备注:这里需要详细看下是如何处理的.....)

  (3)使用锁机制实现原子操作

    锁机制保证了只有获取锁的线程才能操作锁定的内存区域。除了偏向锁,JVM实现锁的方式都用了循环CAS,即当一个线程想进入同步块的时候使用循环CAS的方式来获取锁,当它退出同步块的时候使用循环CAS释放锁。(备注:后半部分,我还得好好理解下...)

  

【java并发编程艺术学习】(五)第二章 java并发机制的底层实现原理 学习记录(三) 原子操作的实现原理学习的更多相关文章

  1. Android艺术开发探索——第二章:IPC机制(下)

    Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvi ...

  2. java并发编程实战笔记---(第二章)线程安全:正确性

    ThreadA__________     同步 ______________ 异步 ___________     异步 ThreadB__________         ____________ ...

  3. 如何评价《Java 并发编程艺术》这本书?

    对于书评这件事情,我其实是不想写的,因为每个人都有自己的一个衡量标准,每个人眼中都有自己的哈姆雷特,是好是坏每个人都褒贬不一.如果对于书中的知识你都掌握了,你只是想把它作为一种知识串联的记忆体的话,那 ...

  4. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  5. java并发编程笔记(五)——线程安全策略

    java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...

  6. Java程序设计(2021春)——第二章课后题(选择题+编程题)答案与详解

    Java程序设计(2021春)--第二章课后题(选择题+编程题)答案与详解 目录 Java程序设计(2021春)--第二章课后题(选择题+编程题)答案与详解 第二章选择题 2.1 面向对象方法的特性 ...

  7. java面向对象编程——第二章 java基础语法

    第二章 java基础语法 1. java关键字 abstract boolean break byte case catch char class const continue default do ...

  8. Android开发艺术探索——第二章:IPC机制(中)

    Android开发艺术探索--第二章:IPC机制(中) 好的,我们继续来了解IPC机制,在上篇我们可能就是把理论的知识写完了,然后现在基本上是可以实战了. 一.Android中的IPC方式 本节我们开 ...

  9. Java Persistence with MyBatis 3(中文版) 第二章 引导MyBatis

    MyBatis最关键的组成部分是SqlSessionFactory,我们可以从中获取SqlSession,并执行映射的SQL语句.SqlSessionFactory对象可以通过基于XML的配置信息或者 ...

随机推荐

  1. eclispse + tomcat 启动是不加载项目的解决办法

    有一个java spring的项目一直好好的,突然一天不能启动了.eclipse的console没有报任何错误,相关的server配置也没有问题,经过一翻折腾顺便还把eclipse从indigo升级到 ...

  2. 机器学习Coursera学习总结

    Coursera上Andrew NG的机器学习实在是太火了,最近有时间花费了20来天的时间(每天3小时左右)终于学习完了全部的课程,总结如下: (1)适合入门,讲的比较基础,Andrew讲的很棒: ( ...

  3. Redis持久化——RDB(一)

    核心知识点: 1.RDB:将当前数据生成快照保存到硬盘 2.手动触发 save:会阻塞Redis服务器直到RDB完成. bgsave:执行fork创建子进程,由子进程负责RDB操作,阻塞只发生在for ...

  4. ERROR 2003 (HY000): Can't connect to MySQL server on 'ip地址' (110)

    用windows能远程连接数据库服务器,用ubuntu就报错,怎么都连不上,报这个错ERROR 2003 (HY000): Can't connect to MySQL server on 'ip地址 ...

  5. Elasticsearch的几种架构(ELK,EL,EF)性能对比测试报告

    Elasticsearch的几种架构性能对比测试报告 1.前言 选定了Elasticsearch作为存储的数据库,但是还需要对Elasticsearch的基础架构做一定测试,所以,将研究测试报告输出如 ...

  6. P3338 [ZJOI2014]力(FFT)

    题目 P3338 [ZJOI2014]力 做法 普通卷积形式为:\(c_k=\sum\limits_{i=1}^ka_ib_{k-i}\) 其实一般我们都是用\(i=0\)开始的,但这题比较特殊,忽略 ...

  7. python有哪些关键字?让他自己“吐”出来!

    通过调用库来输出!for循环控制! 源代码: import keyword c = 0 for i in keyword.kwlist: print(i) c += 1 代码截图: 哈哈,关键字: F ...

  8. JAVA中的4种线程池的使用

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixe ...

  9. Spark- RDD简介

    Spark里面提供了一个比较重要的抽象——弹性分布式数据集(resilient distributed dataset),简称RDD.弹性:数据可大可小,可分布在内存或磁盘,当某台机器宕机时,能够按照 ...

  10. opensource mcu

    1 OpenVCS - Open Source Video Conferencing Server it is used as Multipoint Control Unit (MCU) manage ...