程序猿大牛:分享JAVA并发机制的底层实现原理详解(附电子书籍)

先来熟悉一些术语

内存屏障:是一组处理器指令,用于实现对内存操作的顺序限制。

缓存行:缓存中可以分配的最小存储单元。

原子操作:不可中断的一个或一系列操作。

缓存行填充:当处理器识别到从内存中读取操作数是可缓存的,处理器读取整个缓存航到适当的缓存(L1,L2,L3的或所有)。

缓存命中:如果进行高速缓存航填充操作的内存位置仍然是下次处理器访问的地址是,处理器从缓存中读取操作数,而不是从内存。

写命中:当处理器将操作数写回到一个内存缓存的区域是,首先检查这个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回到内存。

写缺失:一个有效的缓存行被写入到不存在的内存区域。

volatile的应用

volatile是轻量级的synchronized,它只是用来保证共享变量的可见性,不能保证操纵的原子性。

volatile如何实现内存可见性?

深入的说,通过加入内存屏障和禁止重排序优化实现的。

对volatile变量执行写操作时,会在写操作后加入一条store屏障指令。

对volatile变量执行读操作时,会在读操作前加入一条load屏障指令。

volatile保证共享变量可见性

有volatile修饰的变量进行写操作的时候会多出一行汇编代码,该行代码会有一个lock指令。

volatile的两条实现原则:

①: Lock前缀指令会引起处理器缓存会写到内存(使处理器独占任何共享内存)。

②:一个处理器的缓存回写会导致其他处理器的缓存无效。

synchronized的实现原理和应用

synchronized实现同步的基础:

①:对于普通方法,锁是当前实例对象。

②:对于静态同步方法,锁是class对象。

③:同步方法块,锁是synchronized后面括号里的对象。

JVM规范中的实现原理

JVM基于进入和退出Monitor对象实现方法同步和代码块的同步。

Mark Word标记位

synchronized用到的锁是放在JAVA对象头里面的,其中有个Mark Word来存储对象的hashcode、分代年龄和锁标记位,其中锁标记位会产生变化,对应的不同的标记,我们的锁有3种:轻量级锁、重量级锁、偏向锁。

同步原理

代码块同步是使用monitorenter和monitorexit指令实现,monitorenter指令是在编译后插入同步代码块的开始位置,而monitorexit插入到方法结束处和异常处。JVM要保证每个monitorenter必须有monitorexit对应。

Java对象头

长度内容说明

32/64bitMark Word存储对象的hashCode或锁信息

32/64bitClass Metadata Address存储对象类型数据的指针

32/64bitArray Length数组长度(如果当前对象是数组)

无锁状态的Mark Word

锁状态25 bits4 bits1 bit 是否是偏向锁2 bits 锁标志位

无锁状态对象的hashCode对象分代年龄001

有锁状态的Mark Word

锁状态25 bits4 bit1 bit2 bits

23 | 2 bits是否是偏向锁锁标志位

轻量级锁指向栈中锁记录的指针00

重量级锁指向向互斥量的指针10

GC标志空11

偏向锁线程ID | Epoch对象分代年龄101

锁的升级与对比

锁一共有四种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。

①:偏向锁

引入原因:大多数情况下,锁仅有某一线程多次获得,为了使获得锁的代价更低而引入偏向锁。

偏向锁的设置:当某一线程访问同步块时,会在对象头和栈帧中的琐记录里存储锁偏向的线程ID,以后该线程在进入该同步块的时候,不需要再次使用CAS原子操作进行加锁和解锁,只需要简单的测试一下对象头中的Mark Word是否存在指向当前线程的偏向锁。如果测试成功,则表示获得锁,否则检测是否设置有偏向锁,如果没有,则使用CAS竞争锁,否则偏向锁指向该线程。

偏向锁的关闭:在6和7中是默认采用的,可以通过JVM参数关闭:UseBiaseLocking=false,此时程序进入轻量级锁的状态。

②:轻量级锁

加锁:线程执行同步块之前,会在线程私有的栈帧中开辟用于存储锁记录的空间,称为Displaced Mark Word。然后线程尝试将对象Mark Word的替换为指向Displaced Mark Word记录的指针,如果成功,那么当前线程获得锁,如果失败,那么使用自旋获得锁。

何为自旋?

轻量级锁解锁: 使用原子的CAS操作将Displaced Mark Word 替换回对象头,如果成功,表示没有竞争发生,否则,说明当前锁存在竞争(从上图可以看出,竞争锁的线程一直在尝试修改Mark Word,这肯定存在竞争),锁就会膨胀成重量级的锁。

因为自旋会消耗CPU,为了避免太多无用的自旋,一旦锁膨胀成重量级的锁,便不会再恢复到轻量级的锁的状态。当锁处于这个状态下,其他线程试图获取锁时就被阻塞住。当锁释放时再唤醒这些线程。此时醒来的线程就会进行一轮新的竞争。

三种锁的比较:

锁优点缺点使用场景

偏向锁加锁和解锁不需要额外的消耗,和执行非同步方法之间存在纳秒级的差距线程间存在锁的竞争,会带来额外的锁撤销的消耗适用于只有一个线程访问同步块的场景

轻量级锁竞争的线程不会阻塞,提高程序的响应速度自旋消耗CPU追求响应时间,同步块执行速度快

重量级锁线程竞争不使用自旋,不消耗CPU线程阻塞,响应时间慢追求吞吐量,同步块执行速度较长

原子操作的实现原理

处理器实现原子操作的机制:

第一机制:总线锁(声言Lock信号)

第二机制共享缓存锁(修改内存地址,缓存一致性机制:阻止同时修改由2个以上的处理器缓存的内存区域数据)。

JAVA实现原子操作的机制

第一个是循环CAS:JVM中的CAS操纵是利用了处理器提供的CMPXCHG指令实现的。自旋CAS的基本思路是循环进行CAS操作,直到CAS操作成功了为止。

使用锁机制实现原子操作

锁机制保证只有获得锁的线程才能够操作锁定的内存区域。注意:除了偏向锁,JVM实现锁的方式都用了循环CAS操作(使用循环CAS获取锁,使用循环CAS释放锁)。

极简同步技巧

寄存器的效应

计算机必须将数据从主存储器中读到寄存器中,对寄存器操作,然后将数据存放存储器;

当操作系统将某thread分配给CPU时,他会把thread特有的信息加载到CPU的寄存器中;

在分配不同的thread给CPU之前,它会将寄存器的信息存下来。所以thread间决不会共享保存在寄存器的数据;

使用volatile关键字能够保证比那里不会保持在寄存器中,能够保证变量是真正地分享与thread之间。

重排语句的效应

synchronized块能够防止语句的重排,VM不能将语句从synchronized块移动到synchronized块之外。

在这里给大家提供一个交流,讨论的平台,JAVA架构师群671017482

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容

  • 并发系列的文章都是根据阅读《Java 并发编程的艺术》这本书总结而来,想更深入学习的同学可以自行购买此书进行学习。...
    小之丶阅读 865评论 0 10
  • 在现如今的软件开发领域,并发编程是老生常谈的东西。但是要理解并掌握好并发编程却并不是那么容易的事情。对于我来说,在...
    EakonZhao阅读 2,340评论 2 20
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,686评论 0 11
  • 作者/张晓宇 写于2011.2012. 夜深欲卧休,梧兼细雨惆! 伊几时逢得?缘来自会就。 自古京城多骚人,而今...
    张晓宇枫阅读 264评论 1 1
  • 很多年了,叶夏还记得那个夜晚。 “掬水月在手,捻花香满袖”。藤萝架下,只听得声音,两人相遇在月华满地的紫藤园。秋...
    w子归w阅读 257评论 0 0