Java并发编程艺术 -01

小知识

下设计并发程序时会遇到两类资源不够用

  • 硬件资源
    解决方法是搭建集群
  • 软件资源
    使用连接池,比如线程池,数据库连接池,目的就是服用软件资源

volatile实现原理

是站在硬件的层面分析实现原理,记录关键字

  1. Lock前缀指令

  2. 缓存锁定

  3. 缓存一致性

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中关掉偏向锁,程序默认进入轻量级锁状态
    偏向初始化流程
    Java并发编程艺术 -01

2.轻量级锁
Java并发编程艺术 -01

  • 自旋(循环查询)

2.3 原子操作的实现原理

  1. 处理器如何实现原子操作
    处理器提供总线锁定和缓存锁定两个机制来保证复杂 内存操作的原子性。
  • 所谓总线锁就是使用处理器提供的一个 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释放锁。

第3章 Java内存模型