欢迎来到LYBLaoInB的博客
LYBLaoInB
LYBLaoInB
回首往事,不因虚度年华而悔恨,不因碌碌无为而愧疚

java内存模型

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

 

现在的计算机基本都是多核的,比如我用的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这个关键字可以说是很轻量级别的锁了。

 

posted @ 2019-12-04 15:47  LiuYongbo  阅读(268)  评论(0编辑  收藏  举报
<--将网易云歌单中的id复制到上面的data-id中就可以了 http://music.163.com/playlist?id=3103841025&userid=1698529278 -->