zoukankan      html  css  js  c++  java
  • java并发编程的艺术

    java内存模型

    java内存模型的抽象结构

    JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。

    ps:本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。
    [外链图片转存失败(img-J5wut4hX-1567244763245)(https://mawen.coding.net/api/project/161910/files/1689722/imagePreview)]

    从源码到指令序列的重排序

    重排序分为以下三种:

    1. 编译器优化的重排序,编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
    2. 指令级并行的重排序。现代处理器采用了指令级并行技术,将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
    3. 内存系统的重排序。由于处理器使用了缓存(cpu cache)和读/写缓冲区(store buffers),使得加载和存储操作看上去可能是乱序的。

    为了保证内存可见性,Java编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序。

    数据依赖性

    编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

    as-if-serial语义

    as-if-serial语义的意思是:不管怎么重排序,单线程程序的执行结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义

    happens-before简介

    JSR-133使用happens-before的概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系。

    • 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作
    • 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁
    • volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读
    • 传递性:如果A happens-before B,且B happens-before C, 那么A happens-before C

    顺序一致性内存模型

    是一个理论参考模型,再设计的时候,处理器的内存模型和编程语言的内存模型都会以顺序一致性内存模型作为参照

    三个同步原语

    volatile的内存语义

    理解volatile变量的单个读/写,可以看成是使用同一个锁对这些单个读/写做了同步。

    • 可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
    • 原子性。对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种操作不具有原子性。

    volatile写的内存语义如下

    当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。

    volatile读的内存语义如下

    当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来从主内存中读取共享变量。

    volatile内存语义的实现

    • 每个volatile写操作前面插入一个StoreStore屏障。
    • 在每个volatile写操作的后面插入一个StoreLoad屏障。
    • 在每个volatile读操作的后面插入一个LoadLoad屏障。
    • 在每个volatile读操作的后面插入一个LoadStore屏障。

    锁的内存语义(synchronized)

    释放锁的内存语义

    当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。

    获取锁的内存语义

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

    锁内存语义的实现

    ReentrantLock的实现依赖于Java同步去框架AbstractQueuedSynchronzier(AQS)。AQS使用一个整形的volatile变量(Lock实现内存语义的关键)来维护同步状态。

    final域的内存语义

    • 在构造函数内对一个final域的写入,与随后把这个构造对象的引用复制给一个引用变阿亮,这两个操作之间不能重排序。
    • 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
  • 相关阅读:
    FastReport报表控件使用技巧总结
    WinAPI: ShellExecute
    Delphi Excel 操作大全
    DATEADD和DATEDIFF函数、其他日期处理方法 、已打开的端口、FORMAT函数
    javascript-时间戳
    js-jquery-插件开发(二)【最终插件是最后一个,中间是过程】
    js-jquery-插件开发(一)
    Java-idea-eclipse-快捷键【mac,win】
    Java-idea-生成for循环
    Java-idea-设置类头注释和方法注释
  • 原文地址:https://www.cnblogs.com/enhe/p/12141678.html
Copyright © 2011-2022 走看看