锁的内存语义

锁的释放-获取建立的hanppens-before关系

锁是Java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程想获取同一个锁的线程发送消息。

锁的释放和获取的内存语义

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。
当线程获取锁是,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取。
锁和volatile的内存语义相同:

  • 线程A释放一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A堆共享变量所做修改的)消息
  • 线程B获取锁,实质上是线程B接收之前某个线程发出的(在释放着锁之前对这共享变量所做修改的)消息。
  • 线程A释放锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发送消息。

锁内存语义的实现

公平锁在释放锁的最后写volatile变量state,在获取锁时首先读这个volatile变量。根据volatile的hanppens-before规则,释放锁的线程在写voletile变量之前可见的共享变量,在获取锁的线程池读取同一个volatile变量后将立即变得对获取锁的线程可见。
CAS同时具有volatile的读和volatile写的内存语义。
公平锁和非公平锁总结

  • 公平锁和非公平锁释放时,最后都要写一个volatile变量state
  • 公平锁获取时,首先会去读volatile变量
  • 非公平锁获取时,首先会用CAS更新volatile变量,这个操作同时具有volatile读和volatile写的内存语义。

锁释放-获取的内存语义的实现至少有下面两种情况

  • 利用volatile变量写-读所具有的内存语义
  • 利用CAS锁附带的volatile读和写的内存语义

consurrent包的实现

由于Java的CAS同时具有volatile读和volatile写的内存语义,因此Java线程之间的通信现在有了下面4种方式

  • A线程写volatile变量,随后B线程读这个volatile变量
  • A线程写volatile变量,随后B线程用CAS更新这个volatile变量
  • A线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量
  • A线程用CAS和更新一个volatile变量,随后B线程读这个变量

Java的CAS会使用现在处理器上提供的高效机器级别的原子指令,这些原子指令以原子方式对内存执行读-改-写操作,这是在多处理器中实现同步的关键。同时,volatile变量的读/写和CAS可以实现线程之间的通信。把这些特性整合在一起,就形成了整个concurrent爆得以实现的基石。如果我们仔细分析concurrent包的源代码实现,会发现一个通用化的实现模式

  • 首先声明共享变量为volatile
  • 然后使用CAS的原子条件更新来实现线程之间的同步
  • 同时,配合以volatile的读/写和CAS具有的volatile读和写的内存语义来实现线程之间的通信。

AQS,非阻塞数据结构和原子变量类,这些concurrent包中的基础类都是使用这种模式来实现的,而consurrent包中的高层类又是依赖于这些基础类来实现的。从整体来看,consurrent包的实现示意图如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值