Java内存模型

导读:本篇文章讲解 Java内存模型,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

内存模型(Java memory model)

JMM体现在以下几个方面

什么是happen-before

原子性

有序性

可见性

工作内存和主内存的概念

volatile(易变关键字)


内存模型(Java memory model)

简单的说,JMM 定义了一套在多线程读写共享数据时(成员变量、数组)时,对数据的可见性、有序性、和原子性的规则和保障。

JMM即Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。

JMM体现在以下几个方面

·原子性·保证指令不会受到线程上下文切换的影响
·可见性-保证指令不会受cpu缓存的影响
·有序性-保证指令不会受cpu指令并行优化的影响

什么是happen-before

JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。

具体的定义为: 1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么这种重排序并不非法(也就是说,JMM允许这种重排序)。

具体的规则:

(1)程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。

(2)监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。

(3)volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。

(4)传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。 (5)start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。

(6)Join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

(7)程序中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。

(8)对象finalize规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。

原子性

只能采用加锁的方式实现,或者本身这条命令就是原子命令,比如乐观锁中的compareAndSet。

有序性

指令有时候会受cpu指令并行优化的影响,所以有时候需要让指令按顺序执行。

例子,单例模式的双重校验锁写法:必须使用volatile修饰。

public class LazyMan {
    private LazyMan(){

    }

    private static volatile LazyMan lazyman;
    
    public static LazyMan getInstance(){

        if(lazyman==null){
            synchronized (LazyMan.class){
                if(lazyman==null){
                    lazyman =  new LazyMan();
                }
            }
        }
        // 正常顺序  分配内存  new 对象  指针指向堆区
        // 重排顺序  分配内存  指针指向堆区  new 对象
        // 当指针指向堆区的时候  如果有线程 来了 那么 lazyman!=null  直接返回对应的对象
        // 但是这个对象没有创建完毕 所以必须用 volatile修饰
        return lazyman;
    }

    
}

可见性

工作内存和主内存的概念

两个线程都有自己的工作内存,这个工作内存和主线程中的内存不一样。

Java内存模型

volatile(易变关键字)

它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存。

volatile不能保证原子性,仅用在一个写线程,多个读线程的情况,多个线程写的时候也会有 错误只能保证看到最新值,不能解决指令交错.

注意 synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是synchronized是属于重量级操作,性能相对更低。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92802.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!