深入Java内存模型之阅读理解(2)「建议收藏」

深入Java内存模型之阅读理解(2)

大家好,又见面了,我是全栈君。

锁的释放-获取建立的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 关系的图形化表现形式如下:

深入Java内存模型之阅读理解(2)「建议收藏」

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

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

锁释放和获取的内存语义

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

深入Java内存模型之阅读理解(2)「建议收藏」

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

深入Java内存模型之阅读理解(2)「建议收藏」

 

对比锁释放-获取的内存语义与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)来维护同步状态。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107799.html原文链接:https://javaforall.net

(0)
上一篇 2022年3月12日 下午7:35
下一篇 2022年3月12日 下午8:00


相关推荐

  • windows中在 pycharm中安装pytorch

    windows中在 pycharm中安装pytorchwindows中在pycharm中安装pytorch打开pycharm打开file————settings————ProjectInterpreter————点击+号然后点击managerepositories输入以下几个常用的地址最后返回直接搜索pytorch点击Installpackage直接下载即可,可能下载的比较慢。…

    2022年8月29日
    5
  • linkedhashset有序吗_golang人工智能框架

    linkedhashset有序吗_golang人工智能框架一、特征1、继承了HashSet类,底层实现HashMap,数据结构是链表2.保证顺序、唯一、可以为null3.查找较慢、插入删除较快4.线程不同步、多线程使用不安全如果要实现同步的setSetset=Collections.synchronized(newLinkedHashSet(…));二、常用方法参考HashSet三、测试代码publiccla…

    2022年10月12日
    4
  • JS向数组添加元素,插入数据

    js中对于数组的操作很常见,下面记录一下js向数组添加元素的方法。letmyArray=[11,22,33];console.log(‘原数组:’,myArray);myArray.push(44,55);console.log(‘用push在数组后面插入元素:’,myArray);myArray.unshift(66,77);co…

    2022年4月5日
    904
  • postgresql 数据库 alter table alter column set default 的一些实践

    postgresql 数据库 alter table alter column set default 的一些实践os centos7 4db postgresql10 11 创建表后 有时需要对表进行 setdefault 或者 dropdefault 设置 版本 cat etc centos releaseCentO 4 1708 Core su postgres psql c selectversio

    2026年3月16日
    2
  • AI 智能体(AI Agent)的开发费

    AI 智能体(AI Agent)的开发费

    2026年3月19日
    2
  • Unity3D协程介绍 以及 使用[通俗易懂]

    Unity3D协程介绍 以及 使用[通俗易懂]作者ChevyRay ,2013年9月28日,snaker7译 原文地址:http://unitypatterns.com/introduction-to-coroutines/在Unity中,协程(Coroutines)的形式是我最喜欢的功能之一,几乎在所有的项目中,我都会使用它来控制运动,序列,以及对象的行为。在这个教程中,我将会说明协程是如何工作的,并且会附上一些例子来介绍

    2022年6月25日
    31

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号