Java并发编程的艺术 记录(三)

Java内存模型

  并发编程的两个关键问题:

    1.线程之间如何通讯。

    2.线程间如何同步。

  两种方式:共享内存和消息传递。

  Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。

  实例域、静态域和数组元素都存储在堆内存中,堆内存在线程之间共享。Java线程之间的通信由Java内存模型:JMM控制。

  JMM通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供内存可见性保证 。

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

  对于处理器重排序,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障(Memory Barriers,Intel称之为Memory Fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序 。

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

  顺序一致性,可见性保证。所有的操作按程序的顺序执行,而JMM中临界区内的代码可以重排序。

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

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

  ReentrantLock:有公平锁和非公平锁

  Java线程之间的通信4种方式
    1)A线程写volatile变量,随后B线程读这个volatile变量。
    2)A线程写volatile变量,随后B线程用CAS更新这个volatile变量。
    3)A线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量。
    4)A线程用CAS更新一个volatile变量,随后B线程读这个volatile变量

 

posted @ 2018-08-14 15:36  liter7  阅读(122)  评论(0编辑  收藏  举报