Java内存模型与happens-before原则

2019-05-30  本文已影响0人  12点前睡觉hhh

1.JMM简介

当多个线程访问同一个对象的时候,如果不用考虑这些线程在运行时的调度和交替运行,也不需要额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象都会获得正确的结果,那这个对象是线程安全的。
出现线程安全问题一般是因为主内存和工作内存数据不一致重排序导致的,解决线程安全问题最重要的就是理解这两种问题怎么来的,那么,理解它们的核心在于理解java内存模型。

2.内存抽象模型结构

并发编程主要需要解决两个问题:一是线程之间如何通信;二是线程之间如何完成同步。java内存模型是共享内存的并发模型,线程之间通过读-写共享变量完成隐式通信。如果程序员不能理解Java的共享内存模型在编写并发程序时一定会遇到各种关于内存可见性问题。

1.哪些是共享变量
在java程序中所有实例域、静态域和数组元素都是放在堆内存中的(所有线程均可以访问到,是共享的)而局部变量,方法定义参数和异常处理参数不会再线程间共享。共享数据会出现线程安全问题,非共享数据不会出现线程安全问题。

2.JMM抽象结构模型
CPU的处理速度和内存的读写速度不在一个量级,因此每个CPU都会有缓存。共享变量会先存放在主存中,每个线程都有属于自己的工作内存,并把位于主存中的共享变量拷贝到自己的工作内存,之后的读写操作也都是在自己的工作内存进行。并在某个时刻将工作内存的变量写回到贮存。


A与B要进行通信的话,要经过以下步骤:
1.线程A从主存中将共享变量拷贝到自己的工作内存中进行操作,然后将数据写回主存。
2.线程B从主存中读取最新的共享变量。
如果线程A更新数据后,还没来得及进行写回操作,那么线程B读到的就是过期数据(脏读现象)。可以使用同步机制或者volatile关键字来解决这种问题。

3.重排序

在执行程序的时候,为了提高性能,编译器和处理器常常会对指定进行重排序。

4.happens-before规则

这个规则要表达的是:前一个操作的执行结果对后续操作是可见的
happens-before和程序员相关的一共有如下六项,都是关于可见性问题的;

1.程序的顺序性问题

程序前面对某个变量的修改一定是对后续操作可见的。

2.volatile变量规则

一个对volatile变量的写操作happens-before域后续对这个volatile变量的读操作

3.传递性

A Happens-Before B ,B Happens- before C,那么A Happens-Before C

4.管程中锁的规则

管程是一种通用的同步原语,在java指的就是synchronized。
对一个锁的解锁happens-before于后续对这个锁的加锁。

5.线程start规则

主线程A启动子线程B,子线程B能看到主线程在启动子线程B前的操作

6.线程join规则

主线程A等待子线程B完成,当子线程B完成后,主线程能够看到子线程的操作。

上一篇 下一篇

猜你喜欢

热点阅读