• java的内存模型及缓存问题


    一个简单的java内存模型图:

     

    从图中可以看出,当是多核cpu时,每个cpu都有一个独立的高速缓存,多个线程会在多个cpu中独立执行
    当对一个变量只是读操作的时候,jvm自作多情的做了一个优化,只是访问缓存的数据,只有进行写操作的时候,会刷新主内存的数据
    执行如下操作:
    i=1;
    i=i+1;
    cpu1:main memory-->i(1)-->cache(1)-->i+1-->cache-->i(2)-->main memory(2)
    cpu2:main memory-->i(1)-->cache(1)-->i+1-->cache-->i(2)-->main memory(2)
    在两个线程同时执行过程中会出现缓存不一致问题。
    解决方案:
    一、给数据总线加锁:
    总线(数据总线、地址总线、控制总线)
    LOCK#:虽然解决了数据一致问题,但会使得多核cpu串行化执行,效率变低
    二、CPU高速缓存一致性协议(Intel的MESI):
    核心思想:
    1.当CPU写入数据时,如果发现该变量被共享(也就是说,在其他CPU中也存在该变量的副本),会发出一个信号,通知其他的CPU该变量的缓存无效
    2.当其他的CPU访问该变量的时候,重新到主内存中获取


    并发编程的三个重要概念:原子性、可见性、有序性
    原子性:一个操作或者多个操作,要么都成功,要么都失败,中间不能有任何的因素影响终端
    可见性:对同一个变量缓存一致性
    有序性:有序性(顺序性),
    jvm重排序只要求最终一致性,在单线程中可以保证最终一致性,多线程中不能保证


    在java中是怎么保证这三个特性的?
    1.原子性
    对基本数据类型的变量读取和赋值是保证了原子性的,要么都成功,要么都失败,这些操作不可能被中断

    a=10;原子性
    b=a;不满足,1.read a;2.assign b;
    c++;不满足,1.read c;2.add;3.assign c;
    c=c+1;不满足,1.read c;2.add;3.assign c;

    2.可见性
    使用volatile关键字保证可见性

    3.有序性
    happens-before relationship
    3.1 代码的执行顺序,编写在前面的发生在编写在后面的
    -----------------Thread1-------------------
    obj = createObj; 1
    init = true; 2

    -----------------Thread2-------------------
    while(!init) { 1
    sleep();
    }
    useObject 2

    jvm在做优化的时候可能会对两个不相关的变量进行重排序,可能会使Thread1的1和2执行先后顺序改变,
    从而影响Thread2的结果

    3.2 unlock必须发生在lock之后
    3.3 volatile修饰的变量,对一个变量的写操作先于对该变量的读操作
    3.4 传递规则,操作A先于B,B先于C,那么A肯定先于C
    3.5 线程启动规则,线程start方法肯定先于run
    3.6 对象中断规则,interrupt这个动作,必须发生在捕获该动作之前
    3.7 对象销毁规则,初始化必须发生在finalize之前
    3.8 线程终结规则,所有的操作都发生在线程死亡之前

  • 相关阅读:
    leetcode算法题(JavaScript实现)
    使用git submodule管理一个需要多个分立开发或者第三方repo的项目
    linux下从源代码安装git
    git项目实战常用workflow和命令
    如何在linux console中显示当前你在的branch?
    git plumbing 更加底层命令解析-深入理解GIT
    如何直接在github网站上更新你fork的repo?
    git remotes
    git和其他版本控制系统的区别
    Git server安装和配置
  • 原文地址:https://www.cnblogs.com/zheaven/p/12100615.html
Copyright © 2020-2023  润新知