zoukankan      html  css  js  c++  java
  • 并发编程-锁相关的内存语义

    锁的内存语义本质上可以说是对共享变量的更新,能及时让其他线程观察到;并且通过内存屏障,组织编译器或处理器指令重排序,导致多线程下不一致的现象。

    1. volatile内存语义

      见上一篇文章。

    2. 锁的内存语义

    (1)锁的释放和获取的内存语义

      当线程释放锁时,JMM会将本地内存中的共享变量同步到主内存中;

      当线程获取锁时,JMM会将该线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。

    (2)锁内存语义的实现

      ReentrantLock的实现依赖于AbstractQueuedSynchronizer(AQS),AQS使用一个整形的volatile变量(state)来维护同步状态。这个volatile变量是ReentrantLock实现的关键。

      编译器不会对volatile读与其后的任意内存操作重排序不会对volatile写与其前的任意操作重排序。CAS同时具有volatile读和写的内存语义,编译器不会对CAS前和后的任意内存操作重排序,其是通过底层处理器缓存锁定实现原子性的。

    CAS同时具有volatile读和写的内存语义,故Java线程之间的通信存在4种方式:

      ① A线程写volatile变量,随后B线程读该变量;

      ② A线程写volatile变量,随后B线程使用CAS更新该变量;

      ③ A线程使用CAS更新volatile变量,随后B线程使用CAS更新该变量;

      ④ A线程使用CAS更新volatile变量,随后B线程读该变量。

    concurrent包的实现,通用的实现模式:

      ① 声明共享变量为volatile

      ② 使用CAS的原子条件更新来实现线程之间的同步

      ③ 配合以volatile的读/写,及CAS所具有的volatile读和写的内存语义来实现线程间的通信。 

    AQS、非阻塞数据结构和原子变量类,都是使用该模式来实现的。(该图摘自java concurrent包的实现原理

    3. final内存语义

    (1)final重排序规则

      ① 在类实例化时,构造函数中对一个final域的写入,与后边对该类对象的引用之间不能重排序。防止引用到未初始化完全的对象

      首先对象是共享对象如通过static修饰的类实例。JMM禁止编译器将final域的写重排序到构造函数之外;编译器会在final域写入之后,构造函数返回之前插入StoreStore屏障。

      对于普通变量的赋值可能重排序到构造函数之外,此时另一个线程通过该对象访问普通变量时,可能还没有赋值。(具体实例参看《Java并发编程的艺术》)

      ②  初次读一个包含final域的对象,与初次读这个final域之间不能重排序。防止对象引用提前读,而对象还未初始化完全

      在读对象引用和对象final域时,JMM在两者之间插入LoadLoad屏障,禁止读final域重排序到对象引用前边,普通变量可能存在这种情况。

      ③ 对final域是数组或对象等引用类型的情况,有如下约束:在构造函数内对一个final引用的对象的成员域的写入,与随后对该类对象的引用之间不能重排序。

      即final引用的对象中所有成员都写完成后,才可以被其他线程引用。

    (2)禁止在构造函数中将this复制给外边的对象引用,否则可能导致其他线程看到初始化不完全的实例。

  • 相关阅读:
    【转】VS2010中 C++创建DLL图解
    [转]error: 'retainCount' is unavailable: not available in automatic reference counting mode
    [转]关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法
    【转】 Tomcat v7.0 Server at localhost was unable to start within 45
    【转】Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If
    【转】SVN管理多个项目版本库
    【转】eclipse安装SVN插件的两种方法
    【转】MYSQL启用日志,和查看日志
    【转】Repository has not been enabled to accept revision propchanges
    【转】SVN库的迁移
  • 原文地址:https://www.cnblogs.com/shuimuzhushui/p/11336130.html
Copyright © 2011-2022 走看看