Java并发编程艺术 -01
小知识
下设计并发程序时会遇到两类资源不够用
- 硬件资源
解决方法是搭建集群 - 软件资源
使用连接池,比如线程池,数据库连接池,目的就是服用软件资源
volatile实现原理
是站在硬件的层面分析实现原理,记录关键字
-
Lock前缀指令
-
缓存锁定
-
缓存一致性
lock前缀指令将缓存写会内存,并使其他cpu的该地址缓存失效,通过缓存一致性协议来修改内容,并将修改的内容存到当前cpu的缓存中,这样可以保证修改的原子性,这就叫缓存锁定。 其他cpu缓存已经设置为无效标志,通过嗅探来发现一个处理器打算将修改的缓存放到哪个地址,当其他处理器再次调用原来缓存时,检测到缓存失效,会强制执行缓存行填充,将最新的数据填充到缓存中。 这一样就保证了数据的一致性。
volatile使用优化
- LinkedTransferQueue
- 追加字节优化队列出队和入队
synchronized的实现原理与应用
1.Java中的每一个对象都可以作为锁
- 对于普通同步方法,锁是当前实例对象。 ·
- 对于静态同步方法,锁是当前类的Class对象。 ·
- 对于同步方法块,锁是Synchonized括号里配置的对象。
2.实现原理
-
monitorenter必须有对应的monitorexit与之配对(其实就相当于操作系统中的PV操作)
-
任何对象都有 一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。(其实就相当于操作系统中的PV操作)
3.对象头
要理解对象头存储的信息
- HashCode
- 分代年龄
- 锁标记
2.2.2. 锁的升级与对比
为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。
锁一共有4种状态,锁能升级不能降级
- 无锁状态、
- 偏向锁状态、
- 轻量级锁状态
- 重量级锁状态
1.偏向锁
- 测试一下Mark Word中偏向锁的标识是否设置成1
- 等到竞争出现才释放锁的机制
- 在jvm中关掉偏向锁,程序默认进入轻量级锁状态
偏向初始化流程
2.轻量级锁
- 自旋(循环查询)
2.3 原子操作的实现原理
- 处理器如何实现原子操作
处理器提供总线锁定和缓存锁定两个机制来保证复杂 内存操作的原子性。
- 所谓总线锁就是使用处理器提供的一个 LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该 处理器可以独占共享内存
总线锁开销太大,在总线锁期间其他处理器不能访问内存,进而出现使用缓存锁定代替总线锁定来进行优化。
并且在Lock操作期间被锁定,那么当它执行锁操作回写到内存时,处理器不在总线上声 言LOCK#信号,而是修改内部的内存地址,并允许它的缓存一致性机制来保证操作的原子 性,(没懂这是什么意思?)
3.Java如何实现原子操作
(1)使用循环CAS实现原子操作
(2)CAS实现原子操作的三大问题
1)ABA问题
- ABA问题的解决思路就是使用版本号。在变量前面 追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。
- JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题
2)循环时间长开销大。
3)只能保证一个共享变量的原子操作、
- 加锁
- 将多个共享变量合成一个共享变量来操作(两个共享变量i=2,j=a,合并一下ij=2a,)
(3)使用锁机制实现原子操作
- 有意思的是除了偏向锁,JVM实现锁的方式都用了循环 CAS,即当一个线程想进入同步块的时候使用循环CAS的方式来获取锁,当它退出同步块的时 候使用循环CAS释放锁。