• JVM多线程内存模型详解


    JVM多线程内存模型详解

    学习材料来源于网络
    如有侵权,联系删除

    JVM运行时候数据区

    线程独占:每个线程都会有它独立的空间,随线程生命周期而创建和销毁

    线程共享:所有线程能访问这块内存数据,随虚拟机或者GC而创建和销毁

    基于这种内存模型中的多线程操作会出现的问题:

    1、所见非所得

    2、无法肉眼去检测程序的准确性

    3、不同的运行平台有不同的表现

    4、错误很难重现

    示例1

    public class VisibilityDemo {
        private boolean flag = true;
        public static void main(String[] args) throws InterruptedException {
            VisibilityDemo demo1 = new VisibilityDemo() ;
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int i = 0;
                    while (demo1.flag) {
                        i++;
                    }
                    System.out.println(i);
                }
            }).start() ;
            TimeUnit. SECONDS. sleep(  2);
            //设置is为false,使上面的线程结束wh ile循环
            demo1.flag = false;
            System. out.println("被置为false了.");
        }
    }
    

    运行结果出现死循环

    上面的代码在我本机上会出现死循环,如果是CPU缓存带来的问题,那顶多就是在时间上,不能出现太久的死循环。

    工作内存缓存

    指令重排序

    Java编程语言的语义允许编译器和微处理器执行优化,这些优化可以与不正确的同步代码交互,从而产生看似矛盾的行为。

    输出编译后的指令排序

    -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=jit.log
    

    通过汇编后,单个线程的代码在优化上就会出现问题。如下面是汇编后的执行意思。

    int i = 0;
    if(demo1.flag){
        while(true){
            i++;
        }
    }
    

    对于这种问题是在汇编级别上的,本文章不做过多的介绍。

    当然可以关闭代码的JIT编译优化

    -server -Djava.compiler=NONE
    

    内存模型的含义

    内存模型描述程序的可能行为。

    Java编程语言内存模型通过检查执行跟踪中的每个读操作,并根据某些规则检查该读操作观察到的写操作是否有效来工作。

    只要程序的所有执行产生的结果都可以由内存模型预测。具体的实现者任意实现,包括操作的重新排序和删除不必要的同步。

    内存模型决定了在程序的每个点上可以读取什么值。

    Shared Variables共享变量描述

    可以在线程之间共享的内存称为共享内存或堆内存。

    所有实例字段、静态字段和数组元素都存储在堆内存中。

    如果至少有一个访问是写的,那么对同一个变量的两次访问(读或写)是冲突的。

    定义在: https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.1

    附带一个https://docs.oracle.com/javase/8/

    线程操作的定义

    操作定义:
    write要写的变量以及要写的值。
    read 要读的变量以及可见的写入值(由此,我们可以确定可见的值)。lock要锁定的管程(监视器monitor)。
    unlock要解锁的管程。
    外部操作(socket等等..)启动和终止

    程序顺序:如果一个程序没有数据竞争,那么程序的所有执行看起来都是顺序一致的
    本规范只涉及线程间的操作;

    对于同步的规则定义

    对于监视器m的解锁韦所有后续操作对于m的加锁同步

    对volatile变量v的写入,与所有其他线程后续对v的读同步

    启动线程的操作与线程中的第一个操作同步

    对于每个属性写入默认值(0,false,null)与每个线程对其进行的操作同步

    线程T1的最后操作与线程T2发现线程T1已经结束同步。( isAlive ,join可以判断线程是否终结)

    如果线程T1中断了T2,那么线程T1的中断操作与其他所有线程发现T2被中断了同步
    通过抛出InterruptedException异常,或者调用Thread.interrupted或Thread.isInterrupted

    Happens-before先行发生原则

    happens-before 关系主要用于强调两个有冲突的动作之间的顺序,以及定义数据争用的发生时机。

    具体的虚拟机实现,有必要确保以下原则的成立

    • 某个线程中的每个动作都 happens-before该线程中该动作后面的动作。
    • 某个管程上的unlock 动作 happens-before同一个管程上后续的lock动作
    • 对某个volatile 字段的写操作happens-before每个后续对该volatile字段的读操作
    • 在某个线程对象上调用start()方法happens-before该启动了的线程中的任意动作
    • 某个线程中的所有动作happens-before任意其它线程成功从该线程对象上的join()中返回
    • 如果某个动作a happens-before 动作b,且b happens-before动作c,则有a happens-before c.

    当程序包含两个没有被happehs-before关系排序的冲突访问时,就称存在数据争用。
    遵守了这个原则,也就意味着有些代码不能进行重排序,有些数据不能缓存!

    volatile和同步关键字 禁止代码优化和缓存,

    内存模型的含义

    内存模型描述程序的可能行为。

    Java编程语言内存模型通过检查执行跟踪中的每个读操作,并根据某些规则检查该读操作观察到的写操作是否有效来工作。

    只要程序的所有执行产生的结果都可以由内存模型预测。具体的实现者任意实现,包括操作的重新排序和删除不必要的同步。

    内存模型决定了在程序的每个点上可以读取什么值。

    记得加油学习哦^_^
  • 相关阅读:
    OC编程之道-创建对象之工厂方法
    OC编程之道-创建对象之单例模式
    OC编程之道-创建对象之原型模式
    OC编程之道-创建对象之生成器模式
    effective OC2.0 52阅读笔记(七 系统框架)
    effective OC2.0 52阅读笔记(六 块)+ Objective-C高级编程 (二 Blocks)
    effective OC2.0 52阅读笔记(五 内存管理)
    effective OC2.0 52阅读笔记(四 协议与分类)
    安装Sublime Text 3插件的方法
    cocos2d-x学习笔记
  • 原文地址:https://www.cnblogs.com/shaoyayu/p/14073879.html
Copyright © 2020-2023  润新知