『读书笔记』Java并发编程的艺术(并发编程挑战与基石)

第一章 并发编程的挑战

并发编程的目的是为了让程序运行的更快,但是启动更多的线程就能让程序更大限度的运行吗?不一定,CPU通过分配时间片来实现多线程,线程存在上下文切换开销。

  • 那么引起CPU上下文切换的原因都有哪些呢?

    • 当前任务的时间片用完了,cpu正常调度
    • 当前任务发生IO阻塞,被调用线程挂起
    • 多任务抢占锁资源
    • 用户主动挂起
  • 我知道要减少CPU上下文切换次数,我们应该如何做才能减少CPU上下文切换呢?

    • 无锁并发编程
    • CAS
    • 使用最少的线程,避免创建不必要的线程
    • 协程
  • 并发编程会有死锁的问题存在,我们应该如果避免死锁呢?

    • 避免一个线程获取多把锁
    • 避免一个线程在锁内占用多个资源
    • 锁增加过期时间
  • 并发编程除了CPU上下文切换,还有哪些瓶颈与挑战点呢?

    • 硬件资源限制:服务带宽、硬盘读写速度、CPU处理速度...
    • 软件资源限制:数据库连接数、socket连接数、文件句柄数...
  • 对于资源限制的问题,我们应该如果解决呢?

    • 硬件资源限制:集群
    • 软件资源限制:资源池连接复用
    • 根据不同的资源限制调整程序的并发度

第二章 JAVA并发机制的底层实现原理

我们已经知道并发编程都有哪些挑战了,那么java的并发基础机制都有哪些呢?
volatile、synchronize、cas、atomic

  • volatile是一个轻量级的synchronize,他可以阻止指令重排并保证可见性,原理是什么?

    • 为了提高速度,CPU并不直接与内存通信,而是把数据从内存读到高速缓存区,CPU的缓存区的最小存储单位是缓存行
    • 对volatile写操作会增加一行Lock前缀汇编指令,会将当前处理器的缓存行数据写回到系统内存中
    • 其他处理器会检查自己缓存行对应的内存地址是否被修改,如果被修改,会将缓存行数据置为失效状态
    • 缓存行是处理器级别,对于单核CPU,volatile的可见性没有意义,但是volatile的防指令重排还是有用的
    • 一个有意思的操作:对于部分型号的处理器,Lock信号会锁定缓存行,缓存行是64个字节,对于频繁读写的volatile变量,可以通过填充数据到64字节来独占缓存行,volatile写避免与其他数据缓存行互相锁定。(骚操作。。不要用。。)
  • synchronize的锁升级了解一下

    • 锁升级有存在的背景的,HotSpot作者发现大多数情况下,锁不仅不存在多线程竞争,而且还总是被同一线程获取
    • 锁存储于对象头的Mark Word中
    • 锁只能升级,不能降级
    • 偏向锁不会主动解锁,因为锁经常被同一线程获取。
    • 偏向锁加锁过程:检查对象头里是否存有线程ID,如果没有则CAS替换;如果有则检查对象头里线程ID是否是当前线程ID,如果是即表示占用锁;如果不是,申请撤销偏向锁,原偏向锁持有线程会暂时挂起,Mark Word重新偏向于其他线程,最后恢复挂起线程。
    • 上面申请撤销偏向锁过程如果出现竞争,则膨胀成轻量锁
    • 轻量锁加锁过程:线程会在自己栈帧中开辟空间用于存储锁记录,复制锁对象头Mark Word,尝试CAS锁对象头的Mark Word替换为指向栈帧中锁记录指针,如果成功则获取锁,如果失败则CAS自旋竞争锁。
    • 轻量锁解锁过程:线程将自己栈帧锁记录空间中复制的Mark Word重新替换回对象头中,如果失败,表示锁存在竞争,锁会继续膨胀为重量锁。
优点 缺点 适用场景
偏向锁 加锁没有额外开销,性能与不加锁代码相差无几 如果存在锁竞争,解锁有额外的性能消耗 锁竞争场景很少,系统并发低
轻量锁 加锁是CPU自旋操作,不会引发CPU上下文切换,程序响应速度快 如果竞争激烈,CPU自旋消耗大 追求响应速度,同步代码快执行速度很快
重量锁 加锁不会引发CPU自旋 线程阻塞,响应速度较慢 追求高吞吐,CPU不会浪费在自旋上
  • atomic操作原理
    • CPU atomic:处理器会保证读取写入一个字节等基本操作的原子性,对于复杂操作,处理器由以下两种机制保证原子性。针对于以下两种机制,CPU提供多种指令来提供复杂原子操作,如:CMPXCHG指令。
      • 总线锁:当前处理器核心独占共享变量内存,总线锁性能开销比较大
      • 缓存锁:频繁使用的数据会在CPU高速缓存内,那么原子操作就可以在缓存内部执行,并直接修改内存区域,由缓存一致性保证其他核心CPU的缓存行数据一致。
      • 有些处理器不支持缓存锁定;如果数据跨缓存行,不支持缓存锁定。
    • JAVA atomic:JVM中的CAS就是使用CPU提供的原子交换指令CMPXCHG,CAS存在以下三大问题
      • ABA问题:A->B->A,java解决办法:引入版本号。AtomicStampedReference先检查引用是否是预期,再检查版本号是否是预期,最后再把版本号跟引用一起放入Pair内CAS更新。
      • 对于自旋CAS,CPU执行开销大。
      • 只能保证一个共享变量的原子操作,这个可以把多个共享变量包装成一个对象,使用AtomicReference CAS更新。

个人总结

悲观锁的竞争会引起线程上下文切换,乐观锁就是无锁并发编程,可以减少CPU上下文切换,但是会牺牲CPU资源耗用。
线程池内的线程不是越多越好,可以使用jstack jstack pid | grep thread-name -C 1 | grep java.lang.Thread.State | awk '{print $2$3}' | sort | uniq -c来查看线程池内线程状态,如果大部分线程都处于闲置状态,适当减少corePoolSize数量。
并发编程时刻注意资源限制的存在,比如开多线程向数据库insert或者多线程下载网络资源,速度并不一定如预期,有可能反而更慢。

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

推荐阅读更多精彩内容