ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

java内存模型

2019-12-04 15:52:58  阅读:185  来源: 互联网

标签:java 变量 模型 RAM 线程 内存 CPU store


一、计算机的高速缓存模型

 

现在的计算机基本都是多核的,比如我用的8核,上图只有两核。数据最根本当然是存储再硬盘上的,但是硬盘的读取速度很慢。所以都是先将程序运行的数据加载到内存条(RAM中)的。早期的计算机,CPU和RAM是直接交互的,因为早期的CPU的性能还不像现在这样,非常好。有一个叫做摩尔定律的,大概的意思是说现在的科技发展,每间隔18个月,CPU的性能会翻一倍。慢慢的CPU的性能就比RAM高出很多了,这样导致RAM不能很好的发挥CPU的性能。现在的计算机大多都再CPU和RAM之间加了一个CPU高速缓存。但是这个缓存非常贵...如果打开任务管理器,是可以看到的,如下图

 

 二、JMM  JAVA内存模型

 

 了解CPU高速缓存模型是因为JMM和它很像,RAM中存放的是一些程序变量。多个线程可能会共享变量。每个线程都有自己额工作内存。共享变量其实是先复制到工作内存中给线程用,最后再线程操作ok后再保存回去的。但是线程A,B,C如果共享了同一个变量,再不做任何代码级别的操作的时候,他们之间的共享变量副本是不会互相感知的,这个时候就可能出现线程安全相关的问题了。比如下面的代码示例

package com.lyb.jmm;

/**
 * @ClassName Jmm
 * @Description
 * @Author Lyb
 * @Date 2019/12/4 13:48
 * @Version V1.0
 **/
public class Jmm {
    private static boolean isPrepared =false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("waiting data...");
                while(!isPrepared){

                }

                System.out.println("========================== Success");
            }
        }).start();


        Thread.sleep(2000);


        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("prepare data...");
                isPrepared=true;
                System.out.println("prepare Success");
            }
        }).start();
    }


}

预想:两个线程,第一个在等待数据,如果准备好了的标记为true了,退出循环,输出==================== Success,否则一直循环。第二个线程,准备数据,将标记改为true,输出prepare Success。两个线程共享一个isPrepared静态变量。按理说程序会正常走,知道输出==================== Success,但是程序运行结果如下图。

 

 很显然,第一个线程没有感知到第二个线程已经准备数据ok了,没有感知到第二个线程堆isPrepared这个共享变量进行的修改。所以程序运行没有按照我们预想的进行。

解决。我们在这个共享的静态变量上加一个关键字volatile,就可以将线程间不能相互感知的变量变的能相互感知了

 

 

 

 

 

 四、JAVA内存模型中原子操作

 

 

 T1从RAM中read到的共享变量。

读到变量之后load到自己的工作内存中

线程按照代码use变量比如本例中的对变量取反,并while循环空转

T1也是先Read变量,load到工作内存,use,不同的是这里有一个assign赋值操作,会将工作内存中load的值改变为true,然后将改变后的值store到主内存中,最后写回到主内存中write。图中的read和write都是在主内存中的过程,load和store分别是将read到的数据加载到工作内存,将修改后的变量保存到主内存,可以说是两两对立的一种关系。store之后变量已经在主内存中了,图不好画,理解就ok

下图是JMM中的原子操作概念

 

 五、volatile关键字的底层原理

 

 

 看了上面的JMM原子性操作之后,我们就可以来理解volatile关键字了。总线就是连接RAM和CPU之间的连线,可能是主板和CPU,因为RAM大多在主板上。在多核CPU读取主内存的数据的时候其实就是通过总线这个实际的连线进行的。现在的计算机总线基本都回遵循MESI缓存一致性协议。volatile关键字的底层就是每次在改变一个变量的时候,就会立即将这个变量重新store到主内存中,并且在cpu总线嗅觉监听中加上这个变量,当其他线程中也有这个变量的时候,会立即将这个变量失效掉。程序运行的时候发现需要用到的变量被失效了,会重新去内存中读取变量。同时会给这个变量加锁。不过这个锁的粒度很小,就是锁在store的过程中,因为cpu对ram的读取操作时特别快的,所以在这个锁定的时候,其他线程基本无需等待锁的释放,因为其他现在再来读取这个变量的时候store过程基本已经完成了,锁时被释放的状态。(在很久之前的计算机中是对总线加锁的,当一个变量被读取之后,就锁定,等读取这个变量的线程结束了才释放。其他线程才能来读,强行将多线程改为了并列执行)然而volatile这个关键字可以说是很轻量级别的锁了。

 

标签:java,变量,模型,RAM,线程,内存,CPU,store
来源: https://www.cnblogs.com/liuyongbo/p/11983337.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有