当前位置:首页 > 知识普及 > 正文内容

Java虚拟机之Java内存模型

admin16小时前知识普及3

Java虚拟机之Java内存模型

一、Java内存模型

Java的内存模型的建设目的: 为了定义程序中各种共享变量访问规则,其中关于Java内存模型规定如下:

所有的共享变量都存储在主内存中每条线程有自己的工作内存线程的工作内存保存了被该线程使用变量的主内存副本线程对内存的所有操作(读写等)都要在工作内存进行,不能直接操作主内存不同线程间无法访问对方工作内存的变量,线程间变量值传递需要通过主内存来完成

其中,主内存与工作内存 之间的关系可以类比为内存与高速缓冲存储器(cache)

二、交互操作以及注意事项

/**
 * 线程A读到flag为0,让flag为0时,线程A就循环
 * 然后通过主线程修改flag的值
 * 但是程序不能停下来 一直处于运行状态(线程A依旧在循环)
 */
public class JavaMemoryModel {
    static int flag = 0;
    public static void main(String[] args) {
        new Thread( ()->{
            while (flag==0){
            	//代码执行模块
            }
        },"线程A").start();
        try {
            TimeUnit.SECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag=1;
    }
}

1、主内存与工作内存交互操作有8种java虚拟机是什么,如下所示:

lock (锁定): 作用于主内存的变量java虚拟机是什么,把一个变量标识为线程独占状态 (解锁): 作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定read(读取): 作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中Java虚拟机之Java内存模型,以便随后的load动作使用load (载入): 作用于工作内存的变量,它把read操作从主存中变量放入工作内存中use (使用): 作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令 (赋值): 作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中store(存储): 作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中Java虚拟机之Java内存模型,以便后续的write使用write(写入): 作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

2、JMM对这八种指令的使用

为了避免Java虚拟机在运行阶段发生不必要的错误,制定了如下规则:

不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write。不允许线程丢弃他最近的操作,即工作变量的数据改变了之后,必须告知主存。不允许一个线程将没有的数据从工作内存同步回主内存,即未改变数据,又把数据从工作内存写回主内存。一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是对变量实施use、store操作之前,必须经过load,操作。一个变量同一时间只有一个线程能对其进行lock。多次lock后java虚拟机是什么,必须执行相同次数的才能解锁。如果对一个变量进行lock操作,加锁会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或操作初始化变量的值。如果一个变量没有被lock,就不能对其进行操作,也不能一个被其他线程锁住的变量。对一个变量进行操作之前,必须把此变量同步回主内存。 三、特性

是Java虚拟机提供最轻量级的同步机制

1、可见性

是为了保证此变量对所有线程的可见性,下面代码实现了当主线程修改了

/*
*主线程修改flag后,线程A识别flag不为0退出循环
*/
public class JavaMemoryModel {
    static volatile int flag = 0;
    public static void main(String[] args) {
        new Thread(()->{
            while flag==0){
              //代码执行模块 
            }
        },"线程A").start();
        try {

Java虚拟机之Java内存模型 第1张

TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } flag=1; } }

2、不保证原子性

在说不保证原子性之前,先介绍一下原子性,所谓的原子性就是要么同时成功,要么同时失败。

public class AtomicTest {
    static int flag = 0;
    public static void add(){
        flag++;
    }
    public static void main(String[] args) {
        //多线程 执行 flag自增 十万次
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j <10000 ; j++) {
                   add();
                }
            }).start();
        }
        //保证线程都执行完
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(flag);
    }
}

理论上num应该为十万,但是每次都少很多

使用javap -c进行反编译 查看字节码

实际上num++时需要拿到这个静态变量然后操作,操作完再记录回去,在多线程中可能有的线程已经自加了但是还未记录回去,让别的线程读到错误的数量而导致不安全

3、 禁止指令重排序

Java虚拟机的即时编译器有对指令重排序的优化,这就是编译原理中进行代码重新组织。指令重排序: 不影响最终正确结果的情况下,指令执行顺序可能会与程序代码中执行顺序不同。具体步骤如下:

源代码->编译器优化重排->指令并行重排->内存重排->机器执行

进行指令重排时,会考虑数据间的依赖

int x = 0;//1
int y = 4;//2
y = x - 1;//3
x = x * x;//4

我们写的顺序是1234,但是执行的时候可能是2134或1423这都是不影响结果的

但是在多线程中(默认一开始b,c,x,y都是0)

线程A线程B

x = c

y = b

b = 1

c = 2

结果: x = 0, y = 0

重排指令后

线程A线程B

b = 1

c = 2

x = c

y = b

结果: x = 2 , y = 1

在多线程中是不安全的(逻辑上存在的),使用可以禁止指令重排,以防这种情况发生。

CPU指令的作用,使用内存屏障指令重排不能把内存屏障后的指令重排到内存屏障前:

保证特定操作执行顺序(比如禁止指令顺序交换)保证某些变量内存可见性(利用这个实现可见性)

内存屏障是一个lock前缀的空操作,把前面锁住,前面没执行完就不能执行后面

lock前缀空操作的作用: 将本处理器的缓存写入内存中,该写入动作也会引起别的处理器或别的内核无效化其缓存,相当于把缓存中的变量store,write写入主内存中,别的处理器发现缓存无效了立马去主内存中读,就实现了可见性通过这个空操作,实现可见性

lock前缀空操作指令修改同步到内存时,意味着之前操作执行完成,所以指令重排序无法越过内存屏障

四、原子性,可见性与有序性

1、原子性

lock,操作未直接开放给用户,但是提供了字节码指令,来隐式使用lock,(在Java代码中就是关键字)

2、 可见性

- : 保证新值能立即同步到主内存,以及每次使用前立即从主内存刷新

- : 对变量执行前,要先执行store,write操作写入主内存

- final : 被final修饰不能改变所以无须同步可以被其他线程正确访问(引用未逃逸的情况下)

3、 有序性

- : 禁止指令重排

- : 一个变量在同一时刻只允许一条线程对其lock操作 决定持有同一个锁的多个同步块只能串行进入

五、先行发生原则

时间先后顺序于先行发生原则没有因果关系,衡量并发问题不要受时间顺序干扰,一切必须以先行发生原则为准

加入微信交流群:************ ,请猛戳这里→点击入群

扫描二维码推送至手机访问。

版权声明:本文由智汇百科网发布,如需转载请注明出处。

本文链接:https://www.zhihuibkw.com/post/6102.html

分享给朋友:

“Java虚拟机之Java内存模型” 的相关文章

劳荣枝被执行死刑!家属索赔4.8万,法院驳回

劳荣枝被执行死刑!家属索赔4.8万,法院驳回

2023 年 11 月 28 日,随着一声法槌落下,劳荣枝被依法执行死刑,这一轰动全国的案件终于画上了句号。令人意外的是,劳荣枝家属竟提出索赔 4.8 万的诉求,而法院最终驳回了这一请求。这一事件引发了广泛的社会关注和深刻的思考。劳荣枝案历经多年的侦查、审判,其情节之恶劣、手段之残忍,令人发指。她与...

唐山打人案主犯陈继志获刑24年!受害者发声:终于等到

唐山打人案主犯陈继志获刑24年!受害者发声:终于等到

唐山打人案,这起震惊全国的恶性事件,犹如一颗重磅,在社会各界掀起了滔天巨浪。案件的主犯陈继志最终被判处 24 年有期徒刑,这一判决结果,无疑是给受害者以及广大民众一个交代,更是法治社会的正义彰显。受害者们,在那个黑暗的夜晚,他们原本是在享受生活的美好,却无端遭受了陈继志等恶徒的暴力袭击。那血腥的场景...

北大教授呼吁取消英语主科地位!网友:早该如此

北大教授呼吁取消英语主科地位!网友:早该如此

在教育领域,英语一直占据着重要的地位,是众多学生学习的重点科目。近年来,越来越多的声音开始质疑英语的主科地位,认为其在教育资源分配、学生负担等方面存在诸多问题。北大教授的这一呼吁,无疑再次引发了社会各界对英语教育的深入思考。英语作为一门国际语言,其重要性不可否认。在全球化的时代背景下,掌握英语能够为...

掌握灭火器的正确使用

掌握灭火器的正确使用

灭火器,作为一种常见的消防设备,在火灾发生时能够发挥至关重要的作用。它就像是一把守护我们生命财产安全的“利剑”,只有正确掌握其使用方法,才能在关键时刻发挥出最大的效能。我们来了解一下灭火器的种类。目前,市面上常见的灭火器有干粉灭火器、二氧化碳灭火器、泡沫灭火器等。不同种类的灭火器适用于不同类型的火灾...

认识常见的中药材

认识常见的中药材

中药材,是中华民族的瑰宝,承载着千年的医学智慧和文化传承。在我们的生活中,有许多常见的中药材,它们不仅在中医药领域发挥着重要作用,也逐渐走进了我们的日常生活。我们来认识一下人参。人参被誉为“百草之王”,是一种具有极高药用价值的中药材。人参的根呈纺锤形,色泽红棕,质地坚实而沉重。它具有大补元气、复脉固...

如何拍摄美丽的星空

如何拍摄美丽的星空

在浩瀚的宇宙中,星空无疑是最令人着迷的景象之一。那璀璨的星辰、深邃的,仿佛是大自然精心绘制的一幅壮丽画卷。如果你也渴望用相机记录下这神秘而美丽的星空,那么接下来的内容将为你提供一些实用的技巧和建议。一、选择合适的时间和地点拍摄星空的最佳时间通常是在晴朗的夜晚,没有云层遮挡天空。月亮的盈亏也会对星空的...