读《Java并发编程的艺术》(一)

作者: 方腾飞 魏鹏 程晓明

第一章、并发编程的挑战

1、并发编程一定快吗?
不是,当并发执行累加操作不超过百万次时,速度会比串行执行累加操作要慢,因为线程有创建和上下文切换的开销。

2、测试上下文切换次数和时长
(1)Lmbench3可以测量上下文切换的时长
(2)vmstat可测量上下文切换的次数

3、避免死锁的几个常见方法
(1)避免一个线程同时获取多个锁
(2)避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
(3)尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
(4)对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况

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

1、volatile的应用
(1)不会引起线程上下文的切换和调度
(2)写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效
(3)在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态

2、CPU术语定义
(1)内存屏障(memory barries)是一组处理器指令,用于实现对内存操作的顺序限制
(2)缓冲行(cache line)缓存中可以分配的最小存储单位,处理器填写缓存线时会加载整个缓存线,需要使用多个主内存读周期
(3)原子操作(atomic operations)不可中断的一个或一系列操作
(4)缓存行填充(cache line fill)当处理器识别到从内存中读取操作数是可缓存的,处理器读取整个缓存行到适当的缓存(L1、L2、L3的或所有)
(5)缓存命中(cache hit)如果进行高速缓存行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从缓存中读取操作数,而不是从内存读取
(6)写命中(write hit)当处理器将操作数写回到一个内存缓存的区域时,它首先会检查这个缓存的内存地址是否存在缓存行,如果存在一个有效的缓存行,则处理器将这个操作数写回缓存,而不是写回到内存,这个操作被称为写命中
(7)写缺失(write misses the cache)一个有效的缓存行被写入到不存在的内存区域

3、volatile两条实现原则
(1)Lock前缀指令会引起处理器缓存回写到内存,在多处理器环境中,LOCK#信号确保在声明该信号期间,处理器可以独占任何共享内存,缓存一致性机制会阻塞同时修改由两个以上处理器缓存的内存区域数据
(2)一个处理器的缓存回写到内存会导致其它处理器的缓存无效,处理器使用嗅探技术保证它的内部缓存、系统内存和其它处理器的缓存的数据在总线上保持一致

4、volatile的优化
(1)新增一个队列集合类Linked-TransferQueue,在使用volatile变量时,用一种追加字节的方式来优化队列出队和入队的性能。使用64字节的方式填满高速缓冲区的缓冲行,避免头节点和尾节点加载到同一个缓存行,使头、尾节点在修改时不会相互锁定
(2)不是所有的都追加64字节,如果缓存行非64字节宽的处理器、共享变量不会被频繁写,则不适合

5、synchronized锁住的对象
(1)对于普通同步方法,锁是当前实例对象
(2)对于静态同步方法,锁是当前类的Class对象
(3)对于同步方法块,锁是Synchronized括号中配置的对象

6、Java对象头的长度
(1)Mark Word:存储对象的hashCode或锁信息等
(2)Class Metadata Address:存储到对象类型数据的指针
(3)Array length :数组的长度(如果当前对象是数组)

7、Java对象头的存储结构
(1)锁状态 : 无锁状态
(2)25bit : 对象的hashcode
(3)4bit : 对象分代年龄
(4)1bit 是否偏向锁 : 0
(5)2bit 锁标志位 :01

8、锁的升级与比较
(1)锁级别从低到高:无锁、偏向锁、轻量级锁、重量级锁
(2)锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁,这种锁升级却不能降级的策略,是为了提高获得锁和释放锁的效率

9、偏向锁
(1)当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁
(2)偏向锁的撤销是等到竞争出现才释放锁的机制,需要等待全局安全点(在这个时间点上没有正在执行的字节码),会先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否活着,如果线程不处于活动状态,则将对象头设置成无锁状态,如果线程仍然活着,拥有偏向锁的栈会执行

10、三种锁
(1)偏向锁:加速和解锁不需要额外的消耗和执行非同步方法相比仅存在纳秒级的差距;如果线程间存在锁竞争,会带来额外的锁撤销的消耗;适用于只有一个线程访问同步块场景
(2)轻量级锁:竞争的线程不会阻塞,提高了程序的响应速度;如果始终得不到锁竞争的线程,使用自旋会消耗CPU;追求响应速度,同步块执行速度非常快
(3)重量级锁:线程竞争不适用自旋,不会消耗CPU;线程阻塞,响应速度缓慢;追求吞吐量,同步块执行速度较长

11、CPU术语定义
(1)缓存行(cache line):缓存的最小操作单位
(2)比较并交换(Compare and swap):CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换
(3)CPU流水线(CPU pipeline):CPU流水线的工作方式,由5-6个不同功能的电路单元组成一条指令处理流水线,实现一个CPU时钟周期完成一条指令,提高CPU的运算速度
(4)内存顺序冲突(Memory order violation):内存顺序冲突一般是由假共享引起,假共享是指多个CPU同时修改同一个缓存行的不同部分而引起其中一个CPU的操作无效,当出现这个内存顺序冲突时,CPU必须清空流水线

12、处理器如何实现原子操作
(1)使用总线锁保证原子性,总线锁就是使用处理器提供的LOCK#信号,当一个处理器在总线上输出此信号时,其它处理器的请求被阻塞住,该处理器可以独占共享内存
(2)使用缓存锁来保证原子性
(3)不能使用缓存锁情况:当操作的数据不能被缓存在处理器内部,或操作的数据跨多个缓存行时,则处理器会调用总线锁定;有些处理器不支持缓存锁定

13、CAS实现原子操作的三大问题
(1)ABA问题
(2)循环时间长开销大
(3)只能保证一个共享变量的原子操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值