【java并发编程艺术学习】(五)第二章 java并发机制的底层实现原理 学习记录(三) 原子操作的实现原理学习
章节介绍
主要包括 术语定义、处理器如何实现原子操作、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并发机制的底层实现原理 学习记录(三) 原子操作的实现原理学习的更多相关文章
- Android艺术开发探索——第二章:IPC机制(下)
Android艺术开发探索--第二章:IPC机制(下) 我们继续来讲IPC机制,在本篇中你将会学习到 ContentProvider Socket Binder连接池 一.使用ContentProvi ...
- java并发编程实战笔记---(第二章)线程安全:正确性
ThreadA__________ 同步 ______________ 异步 ___________ 异步 ThreadB__________ ____________ ...
- 如何评价《Java 并发编程艺术》这本书?
对于书评这件事情,我其实是不想写的,因为每个人都有自己的一个衡量标准,每个人眼中都有自己的哈姆雷特,是好是坏每个人都褒贬不一.如果对于书中的知识你都掌握了,你只是想把它作为一种知识串联的记忆体的话,那 ...
- [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers
本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
- Java程序设计(2021春)——第二章课后题(选择题+编程题)答案与详解
Java程序设计(2021春)--第二章课后题(选择题+编程题)答案与详解 目录 Java程序设计(2021春)--第二章课后题(选择题+编程题)答案与详解 第二章选择题 2.1 面向对象方法的特性 ...
- java面向对象编程——第二章 java基础语法
第二章 java基础语法 1. java关键字 abstract boolean break byte case catch char class const continue default do ...
- Android开发艺术探索——第二章:IPC机制(中)
Android开发艺术探索--第二章:IPC机制(中) 好的,我们继续来了解IPC机制,在上篇我们可能就是把理论的知识写完了,然后现在基本上是可以实战了. 一.Android中的IPC方式 本节我们开 ...
- Java Persistence with MyBatis 3(中文版) 第二章 引导MyBatis
MyBatis最关键的组成部分是SqlSessionFactory,我们可以从中获取SqlSession,并执行映射的SQL语句.SqlSessionFactory对象可以通过基于XML的配置信息或者 ...
随机推荐
- 在Nginx/Openresty中启用http2支持
转自个人博客 chinazt.cc 以下摘自http2的介绍: HTTP/2 源自 SPDY/2 SPDY 系列协议由谷歌开发,于 2009 年公开.它的设计目标是降低 50% 的页面加载时间.当下很 ...
- android 自定义progressbar 样式
在res下创建drawable文件夹,新建文件drawable/progressbar_color.xml <layer-list xmlns:android="http://sche ...
- Java并发之ArrayBlockingQueue
ArrayBlockingQueue是一个由数组支持的有界阻塞队列.此队列按 FIFO(先进先出)原则对元素进行排序.队列的头部是在队列中存在时间最长的元素.队列的尾部是在队列中存在时间最短的元素.新 ...
- 云计算服务的三种类型(SaaS、PaaS、IaaS)
云计算可以帮助企业降低IT方面的成本和复杂性,并获得他们蓬勃发展所需的灵活性与敏捷性.但是,规划出通往云的明确路径并非易事.毕竟用户需要看透与云相关的市场大肆宣传,然后理解并分析不同种类的云计算模式的 ...
- Python赋值魔法技巧
实验环境: [root@localhost ~]# python -V Python 2.7.5 1.序列解包 多个赋值操作可以同时进行 >>> x,y,z = 1,2,3 > ...
- LeetCode:乘法表中的第K小的数【668】
LeetCode:乘法表中的第K小的数[668] 题目描述 几乎每一个人都用 乘法表.但是你能在乘法表中快速找到第k小的数字吗? 给定高度m .宽度n 的一张 m * n的乘法表,以及正整数k,你需要 ...
- rails dependent
dependent 可以設定當物件刪除時,也會順便刪除它的 has_many 物件: class Event < ActiveRecord::Base has_many :attendees, ...
- 利用CocoaPods管理本地工程和发布开源框架
发布自己三方框架 发布云端库 1.创建spec pod spec create xxx 2.编辑spec s.name:名称,pod search 搜索的关键词,注意这里一定要和.podspec的名称 ...
- 【Flask模板】宏的概念和基本使用
# 宏:模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量.使用宏的时候,参数可以为默认值.相关示例代 ...
- 20145229吴姗珊两天小总结 《Java程序设计》第4周学习总结
20145229吴姗珊两天小总结 <Java程序设计>第4周学习总结 教材学习内容总结 由于自己的基础不好对知识的理解不透彻,所以这两天的学习还是集中在第六章和第七章,对知识点多了一点理解 ...