zoukankan      html  css  js  c++  java
  • 了解Java内存模型,看完这一篇就够了

    前言(此文草稿是年前写的,但由于杂事甚多一直未完善好。清明假无事,便收收尾发布了)

        年关将近,个人工作学习怠惰了不少。两年前刚做开发的时候,信心满满想看看一个人通过自己的努力,最终能达到一个什么样的高度。而近半年

    深陷生活的泥淖中,却有点被压迫住的感觉。个人成长、家庭、父母、朋友、身边的人,无不或多或少的影响着我的心境。很多时候还是要多反思一些,

    通过思考让自己重拾信心,继续打满鸡血的前行。中国当前的大环境纵然有波折,但总体是向上的,互联网行业也是出于深度改造各行各业的状态,而且

    个人对计算机对编程很有热情,一息理想尚存,想要自己的人生有所不同。所以不管怎样,这条路还要好好的走下去。这个把月多学习吧,为节后的

    机会最好准备。

    正文

        闲话少叙,下面开始正题。首先要明确内存模型指什么。书中的定义是:在特定的操作协议下,对特定内存和高速缓存进行读写访问的过程抽象

    可以知道,内存模型就是来规定如何对内存/缓存进行读写操作的。所以Java内存模型,就是用来定义程序对java内存的的访问规则。进一步说, java内存

    模型就是定义程序中变量(静态变量、数组对象元素等,不包括局部变量、方法参数)的访问规则。

    Java内存模型的规定:

    1、所有变量存储在主内存中;

    2、每个线程都有自己的工作内存,且对变量的操作都是在工作内存中进行;

    3、不同线程之间无法直接访问彼此工作内存中的变量,要想访问只能通过主内存来传递。

    java的线程、工作内存、主内存关系如下图所示:

    具体变量从主内存到工作内存,以及从工作内存转回主内存的实现细节,由下面八个原子性的操作完成:

    lock:作用于主内存变量,将该变量标识为一个线程独占的状态

    unlock:作用于主内存变量,将独占状态释放

    read:作用于主内存变量,将值拷贝到工作内存中

    load:作用于工作内存中的变量,将值放到工作内存中的变量副本中

    use:作用于工作内存中的变量,将值传给执行引擎

    asign:作用于工作内存中的变量,将执行引擎中的值赋给工作内存中的变量

    store:作用于工作内存中的变量,将值传给主内存

    write:作用于主内存中的变量,将工作内存中返回的值放到主内存变量中

    同时还对上述八个操作进行了一些细节的要求,比如read/load、store/write必须成对出现,未执行过lock的变量不能执行unlock操作等。

    划重点,此处面试常遇到的问题就是对于volatile关键字的解读。

    volatile关键字

    此关键字修饰的变量具有两种效果:1、保证线程间的可见性;2、阻止指令重排序

    对于1的实现,它保证load与use必须相邻调用,即要use这个变量,必定先执行read/load,这样每次都能获取到最新的变量值;它又保证asign与store

    必须相邻调用,即在工作内存中将该变量改了之后,必定会先同步到主内存中。这样,volatile关键字实现了可见性。至于阻止指令重排序,还是移步

    《深入理解java虚拟机》一书吧,贫道水平有限,就不在这里说了。

    从另一个角度来分析,Java内存模型是围绕着在并发过程中如何处理原子性、可见性、有序性来建立的。

    原子性:八个原子性操作,以及synchronized(lock/unlock未直接开放给用户,synchronized通过monitorenter跟monitorexit指令调用的lock/unlock操作)

    可见性:volatile、synchronized、final这三个关键字均通过不同方式实现了可见性

    有序性:volatile、synchronized  这两个关键字保证有序性,同时还有先行发生(happens-before)原则来保证隐含的默认有序性

    下面说说happens-before先行发生原则,先行发生原则用通俗语言表述就是:如果操作A在操作B之前发生,那么A产生的影响B同样能观测到。那么问题来

    了,先行发生原则都有哪些呢?同样有八条,如下:

    程序次序规则:同一个线程中按照代码的顺序依次执行

    管程锁定规则:对于同一个锁,unlock先行发生于后面的lock,即unlock了才会lock

    volatile变量规则:对一个volatile变量的写操作先行发生于后面对该变量的读操作,即写完了才会读

    线程启动规则:一个线程的start()方法先行发生于此线程的任何一个动作

    线程终止规则:一个线程的所有动作先行发生于该线程的终止检测

    线程中断规则:对一个线程interrupt()方法的调用先行发生于线程的中断检测Thread.interrpted()

    对象终结规则:对象的初始化完成先行发生于finalize()方法

    传递性:顾名思义,A先行发生于B,B先行发生于C,则A一定先行发生于C

    总结

        java内存模型基本就这些内容,如果都掌握了的话,非一线互联网公司基本都能应对自如了(因为一线互联网公司贫道本人也没进去><)。

  • 相关阅读:
    大三学长带我学习JAVA.作业8。。1 有1、2、3、4这几个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
    详解Manifest
    反射机制和配置文件的用法
    大三学长带我学习JAVA.作业8。 判断101200之间有多少个素数,并输出所有素数。
    序曲
    java打包生成jar和exe全过程
    大三学长带我学习JAVA.作业6 编写日历表 和vim
    大三学长带我学习JAVA.作业7 利用for循环打印 9*9 表
    动态代理类
    pku 3522 Slim Span
  • 原文地址:https://www.cnblogs.com/zzq6032010/p/10328399.html
Copyright © 2011-2022 走看看