前言

今天的笔记来了解一下原子操作以及Java中如何实现原子操作。

概念

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

处理器实现原子操作

处理器会保证基本内存操作的原子性。处理器保证从系统内存中读取或者写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址。最新的处理器能自动保证单处理器进行16/32/64位的操作是原子的,并且提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。

使用总线保证原子性

如果有多个处理器同时对共享变量进行操作,那么共享变量就会被多个处理器同时操作,这样的话,读改写操作就不是原子的。
比如i=1,i++,两个处理器同时进行操作,最后的结果,可能是3,也可能是3.
原因可能是多个处理器同时从各自的缓存中读取变量i,分别进行加1操作,然后分别写入系统内存。
处理器使用总线锁来解决这个问题。当处理器发出LOCK#信号时,其他处理器的请求会被阻塞主,该处理器可以独占共享内存。

使用缓存锁定来保证原子性

锁总线开销还是很大的,锁住了CPU和内存之间的通信。
因为频繁使用的内存会缓存在处理器的L1、L2、L3高速缓存中,原子操作可以在缓存内部完成,同时通过缓存一致性协议,当A处理器修改缓存中的i时,其他处理器不能同时缓存i,即会使得其他处理器中对于共享变量的缓存失效。
这段还不是特别明白,感觉得重新翻一下操作系统,有知道的网友可以留言补充一下。

Java实现原子操作的方式

Java可以使用锁,实现一段代码的原子操作。但这样开销比较大,会引起频繁的上下文切换。
另外一种方式就是使用CAS操作(比较交换)。
CAS算法的过程是比较简单的。它会包含三个参数(V,E,N))。V表示要更新的变量,E表示预期值,N值。当且仅当V等于E值时,才会将V的值设为N,如果V值和E值不同,说明已经有其他线程做了更新,则当前线程什么都不做。
当多个线程同时使用CAS对变量进行操作时,只有一个会胜出并成功更新,其余会失败。失败的线程不会被挂起。
Java中对于基本类型的包装类都有对应的原子操作实现,比如
AtomicBoolean
AtomicInteger

如果拿AtomicInteger为例子,其中的incrementAndGet的实现如下所示,是直接调用了Unsafe类的方法:

 public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;}复制代码

其中var1是传入对象的引用,var2是字段到对象头部的偏移量,方便快速定位,var5是当前值,var5+var4就是期望值,var4传入的是1。
如果是引用类型的话,可以使用AtomicReference。
CAS操作虽好,但它会遇到ABA问题,即一个变量先是A,后来变成了B,在比较时又变回了A,但CAS操作无法感知到这种情况,如果说我们是否可以修改当前值,不仅取决于当前值,还取决于它的变化,那么原有的CAS操作就无能为力了,因为它感知不到。
贴心的JDK为我们提供了AtomicStampedReference,它在对象内部维护了时间戳,当更新数据时,不仅要更新数据,还要更新时间戳。当AtomicStampedReference设置对象值时,对象值以及时间戳都必须满足期望值,写入才会成功。
如果是数组类型的话,JDK提供了AtomicIntegerArray等数组类型的原子类。

【Java并发编程的艺术】第二章读书笔记之原子操作相关推荐

  1. 《Java并发编程实践-第一部分》-读书笔记

    大家好,我是烤鸭: <Java并发编程实战-第一部分>-读书笔记. 第一章:介绍 1.1 并发历史: 多个程序在各自的进程中执行,由系统分配资源,如:内存.文件句柄.安全证书.进程间通信方 ...

  2. 《Java并发编程的艺术》——线程(笔记)

    文章目录 四.Java并发编程基础 4.1 线程简介 4.1.1 什么是线程 4.1.2 为什么要使用多线程 4.1.3 线程优先级 4.1.4 线程的状态 4.1.5 Daemon线程 4.2 启动 ...

  3. Java并发编程的艺术-阅读笔记和思维导图

    最近在坚持每天阅读<<Java并发编程的艺术>>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思 ...

  4. 【Java并发编程的艺术】读书笔记——Java并发编程基础

    学习参考资料:<Java并发编程的艺术> 文章目录 1.线程的几种状态 2.如何安全的终止线程 3.线程间通信(重要) 3.1共享内存 3.2消息传递 1.线程的几种状态 线程在运行的生命 ...

  5. Java并发编程的艺术_Conc

    Java并发编程的艺术 1 并发编程的挑战 1.1 上下文切换 即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制.时间片是CPU分配给各个线程的时间,因为时间片 ...

  6. [书]java并发编程的艺术笔记

    本文属于自己整理的读书笔记,便于回顾.内容绝大部分来自书籍:java并发编程的艺术,版权归原作者所有. 第1章 并发编程的挑战 1.多线程一定比单线程快? 不一定,如同在同时阅读两本书时的来回切换切换 ...

  7. 《Java并发编程的艺术》笔记

    <Java并发编程的艺术>笔记 第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种 ...

  8. 《JAVA并发编程的艺术》之Java内存模型

    <JAVA并发编程的艺术>之Java内存模型 文章目录 <JAVA并发编程的艺术>之Java内存模型 Java内存模型的基础 并发编程模型的两个关键问题 Java内存模型的抽象 ...

  9. Java并发编程的艺术(一)

    看<java并发编程的艺术>这本书,想着看的时候做个简单的总结,方便以后直接看重点. 一.并发编程的挑战 1.上下文切换 Cpu时间片通过给每个线程分配CPU时间片来实现多线程机制,时间片 ...

最新文章

  1. 来自顶尖JAVA程序猿的焦虑,拒绝中年危机,唯有一生力学笃行
  2. C++中的动态内存分配
  3. Tomcat虚拟目录配置
  4. python自学网站有哪些-Python学习网站有哪些?Python基础教程网站推荐
  5. 哪种代理适合用于Web数据采集
  6. intent隐式和显式_Neo4j:使隐式关系成为显式和双向关系
  7. 《Bash 脚本教程》免费发布啦,开源!
  8. 新媒体中的MCN机构是什么意思
  9. Code::Blocks 16.01 改变注释的的颜色
  10. 樊登读书分享ppt_樊登读书精华分享-《分手后,成为更好的自己》
  11. pyltp的使用教程
  12. redis搭建集群时报错CLUSTERDOWN Hash slot not served
  13. java分析内存泄露工具_AIL-Framework下载-java内存泄露分析工具(Information Analysis Leaks)-东坡下载...
  14. Java的sort用法深究,compare按照姓氏排序
  15. 注意收藏 !2022年下半年软考时间都在这
  16. 网页设计之标题栏显示当前系统日期
  17. python 录音左右声道_Python分离立体声wav压缩文件的左右声道
  18. python之 logging模块详细使用【转载】
  19. SpringCloud——服务接口(api)
  20. 基于stm32f407的无线视屏传输项目

热门文章

  1. 使用Mongo Shell和Java驱动程序删除MongoDB的示例
  2. C# 窗体全透明,控件不透明
  3. 开课吧Java课堂:如何通过接口引用实现接口?
  4. 行业深度见解•SD-WAN对于企业云的重要性 1
  5. 唠唠SE的IO-03——字符输入输出流
  6. centos6.5 nginx开机启动
  7. 微软 SQL Server 2016 SP1 开发者版入驻 Windows 容器
  8. 定时执行失败原因分析
  9. 【回文串3】LeetCode 125. Valid Palindrome
  10. Matlab之subplot函数