聊聊并发编程-java内存模型

上一节中讲了可见性,原子性和有序性问题产生的源头。这一节我们就来讲讲如何解决可见性,有序性问题。

 

通过上节我们知道可见性是由于CPU缓存引起的,有序性是由于编译器重排优化引起的。

那么解决可见性和有序性最简单的方案就是禁用CPU缓存和禁止指令重排。但是如果我们直接粗暴的禁止也就享受不了CPU缓存和指令重排带来的性能优化的成果了。最好的办法是能够提供禁止使用CPU缓存和指令重排的方法,由我们程序员自己决定什么时候禁止这些。那么有没有这些方法呢?庆幸的是java已经为我们考虑了这点。也就是我们接下来要讲的JMM。

 

一、java内存模型(JMM)

 

说起java内存模型,大家可能首先联想到的是java的内存结构(JVM内存结构)。很多人误以为两者是一回事,其实不然。

 

JMM并不像JVM内存结构真实存在的,它是一个抽象概念。JMM是和多线程相关的,他描述了一组规范,主要是围绕解决在并发过程中如何处理可见性、原子性和有序性来建立的。它定义了一些语法集,映射到java语言就是volatile、synchronized和final三个关键字,以及六项Happens-Before规则。本质上可以理解为JMM规范了如何提供按需禁止CPU缓存和指令重排的方法。

 

 

一、volatile关键字的作用

 

当用volatile来声明一个变量时候

volatile int a=0

它意味着:告诉编译器,对于这个变量的读写不能使用cpu缓存。必须从内存中读取和写入。同时禁用指令重排

 

二、Happens-Before规则

 

这个不要望文生义(先行发生),它要表达的意思是:前面一个操作的结果对后续操作是可见的。

 

1、程序的顺序性规则

同一线程中前面的操作Happens-Before后面的操作。保证了程序的顺序执行,即我们编写的代码前面的语句Happens-Before后面的语句

int a=1;

int b=1;

P p = new P();

这里可能会有个疑问:程序的顺序性规则是否意味着就全面禁用了指令重排呢?个人理解是不会的。这里规则保证的是高级语言的一条语句的action Happens-Before后面的语句。例如这里的第3句,会对应多条CPU指令。1.申请内存,2.初始化,3.绑定变量地址。这里的2,3是没有先后依赖关系的可以进行指令重排

 

2、volatile变量规则

对volatile字段的写入操作Happens-Before于后续每一个读操作

 

3、传递性

如果A动作Happens-Before B动作,B动作Happens-Before C动作,那么A Happens-Before C

 

4、管程中锁的规则

对于一个锁的解锁Happens-Before于后续对这个锁的加锁

 

5、线程start()规则

它是指主线程A启动子线程B后,B线程能够看到主线程在启动子线程B前的操作当然指的是共享变量。

public void A(){

    x=0;

    Thread B = new Thread();

    B.start();

}

B线程能够看到A方法启动B之前所有的操作

 

6、线程join()规则

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

public void A(){

    Thread B = new Thread(

        public void run(){

            x=0;

        }

    );

    

    B.start();

    B.join();

}

 

 

为了更好的理解这6条规则,大家看看如下会是什么值?为什么?

 

public class A{

    private int x=0;

    private volatile y =0;

    

    public void write(){

        x=1;

        y=2;

    }

    

    public void read(){

        if(y ==2){

            //x的值是多少

        }

    }

}

 

公众号
欢迎关注分享

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值