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

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

下面是锁释放-获取的示例代码:

class MonitorExample {
int a = 0; public synchronized void writer() { //1
a++; //2
} //3 public synchronized void reader() { //4
int i = a; //5
……
} //6
}

假设线程A执行writer()方法,随后线程B执行reader()方法。根据happens before规则,这个过程包含的happens before 关系可以分为两类:

  1. 根据程序次序规则,1 happens before 2, 2 happens before 3; 4 happens before 5, 5 happens before 6。
  2. 根据监视器锁规则,3 happens before 4。
  3. 根据happens before 的传递性,2 happens before 5。

上述happens before 关系的图形化表现形式如下:

在上图中,每一个箭头链接的两个节点,代表了一个happens before 关系。黑色箭头表示程序顺序规则;橙色箭头表示监视器锁规则;蓝色箭头表示组合这些规则后提供的happens before保证。

上图表示在线程A释放了锁之后,随后线程B获取同一个锁。在上图中,2 happens before 5。因此,线程A在释放锁之前所有可见的共享变量,在线程B获取同一个锁之后,将立刻变得对B线程可见。

锁释放和获取的内存语义

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。以上面的MonitorExample程序为例,A线程释放锁后,共享数据的状态示意图如下:

当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须要从主内存中去读取共享变量。下面是锁获取的状态示意图:

对比锁释放-获取的内存语义与volatile写-读的内存语义,可以看出:锁释放与volatile写有相同的内存语义;锁获取与volatile读有相同的内存语义。

下面对锁释放和锁获取的内存语义做个总结:

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

ReentrantLock的实现:

class ReentrantLockExample {
int a = 0;
ReentrantLock lock = new ReentrantLock(); public void writer() {
lock.lock(); //获取锁
try {
a++;
} finally {
lock.unlock(); //释放锁
}
} public void reader () {
lock.lock(); //获取锁
try {
int i = a;
……
} finally {
lock.unlock(); //释放锁
}
}
}

在ReentrantLock中,调用lock()方法获取锁;调用unlock()方法释放锁。

ReentrantLock的实现依赖于java同步器框架AbstractQueuedSynchronizer(简称之为AQS)。

AQS使用一个整型的volatile变量(命名为state)来维护同步状态。

最新文章

  1. [C#] C# 知识回顾 - 序列化
  2. IQueryable和list本地集合区别
  3. wp8 入门到精通 Animation 背景加字体颜色从下向上变化颜色效果
  4. C#—WebService
  5. hbase基本操作
  6. 原生js获取鼠标坐标方法全面讲解:clientX/Y,pageX/Y,offsetX/Y,layerX/Y,screenX/Y【转】
  7. Base62编码与62进制
  8. .net又一个生成缩略图的方法,不变形,非常好用
  9. ECshop使用财付通接口支付时出现“[3006]您的请求无效,请重新再试
  10. SQL Server 2008 R2 性能计数器详细列表(二)
  11. 微信小程序- 生成二维码
  12. iOS UICollectionView(转一) XIB+纯代码创建:cell,头脚视图 cell间距
  13. linux 关于Apache默认编码错误 导致网站乱码的解决方案
  14. ubuntu16.04 安装java
  15. Spring Security的核心拦截器
  16. 2019.02.11 bzoj3165: [Heoi2013]Segment(线段树)
  17. 有趣的filter
  18. Wix中注册c#开发的Activex控件
  19. mysql索引提高查询速度
  20. Java的StringBuIlder扩容机制

热门文章

  1. vsftp安装与配置for Linux
  2. .net core 3.0视图动态编译
  3. 查询返回JSON数据结果集
  4. java获取文件列表,并按照目录的深度及文件名的拼音的升序排列
  5. [Canvas]Bombman v1.00
  6. 浅谈压缩感知(二十二):压缩感知重构算法之正则化正交匹配追踪(ROMP)
  7. Machine、Swarm、Compose、SocketPlane这些Docker生态圈软件各解决了哪些问题?
  8. springboot mybatis pagehelper 分页问题
  9. nginx https 配置样例
  10. CoffeeScript简介 <一>