从计算机底层来解析java内存结构!

题主在写这篇文章之前,写了一小段程序,如下:

public class Demo05 extends Thread{
    //初始状态为true
    private boolean status = true;

    //设置状态
    public void setStatus(boolean status) {
        this.status = status;
        System.out.println("我已经将status的状态改变了");
    }
    //重写run方法
    public void run() {
        System.out.println("进入run方法了。。。");
        while (status) {

        }
        System.out.println("线程停止了。。。");
    }


    public static void main(String[] args) throws InterruptedException {
        //创建一个对象
        Demo05 d = new Demo05();
        d.start();
        //沉睡三秒钟
        Thread.sleep(3000);
        //然后将status的状态设置为false
        d.setStatus(false);

        //然后此时在打印status的状态
        System.out.println("当前的status的状态为:"+d.status);
        }
}

你也可以先猜想一下,程序的运行结果是什么?
这个程序的意思就是,我先开启线程,线程执行,调用run方法,然后在让主线程睡三秒中,在将状态设置为false。
猜想一下,会发生什么?
我刚开始猜想的是,程序最终打印false,程序最终会终止执行。
然而,事实证明我的猜想不对,最终的结果确实打印出stauts的状态为false,然后程序依然处于运行状态。

由此上程序可以知道,在main方法的主线程将status的状态设置为false的时候,d线程并不知道,status的值已经发生变化了。

然而,我们希望的结果是,在将status的值设置为false的时候,d线程知道我们的status状态,然后根据此状态来执行相应的操作。
所以,接下来,我在status变量前面加了volatile关键字。
于是程序变成了下面的样子:

package com.bjsxt.synchroized;
/**
 * volatile关键字
 * 作用:使变量在多个线程之间可见
 * 引出?线程的工作原理?
 * 在java中每一个线程在启动都会有自己的一块工作内存,存放所有主内存中变量的值的copy。
 * 也就是在这个代码中;
 * 在线程启动时,这里有个内存区域,此时这个变量是true或者false。将这个值copy在线程工作内存中。
 * 
 * 引出问题?java内存模型与线程
 * 不希望处理器在大部分时间里都处于等地啊其他资源的状态,就必须使用一些手段去把处理器的运算能力
 * 压榨出来。否则就会造成很大的浪费
 * 然而,让计算机同时处理几项任务则是最容易想到的、也证明是非常有效的压榨手段。
 * @author 莱格
 *
 */
public class Demo05 extends Thread{

    private volatile boolean status = true;

    //设置状态
    public void setStatus(boolean status) {
        this.status = status;
        System.out.println("我已经将status的状态改变了");
    }
    //重写run方法
    public void run() {
        System.out.println("进入run方法了。。。");
        while (status) {

        }
        System.out.println("线程停止了。。。");
    }


    public static void main(String[] args) throws InterruptedException {
        //创建一个对象
        Demo05 d = new Demo05();
        d.start();
        //沉睡三秒钟
        Thread.sleep(3000);
        //然后将status的状态设置为false
        d.setStatus(false);

        //然后此时在打印status的状态
        System.out.println("当前的status的状态为:"+d.status);
        /**
        未加volatile关键字之前:
         * 最终将结果打印出来了,打印出false,但是此时的变量是不可见的,意思是,当status的状态发生变化时
         * run方法不可知的。
         * 所以程序一直处于阻塞状态。
         * 加了之后:
         * 接下来,我在变量上面加了volatile关键字之后
         * 奇迹异常发生了,此时的状态 对于status来说,是可见的。
         * 然后程序退出了。
         */
    }

}

最终的结果是,程序执行完毕,打印出false,并且,程序退出了。

由此引发了我对java虚拟机内存模型的探索?

在说java内存模型之前,我们先来探讨一个问题?

在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力太强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通讯子系统速度的差距太大,他部分时间都花在了磁盘的IO,网络通讯,和数据访问上了?

然而,我们不希望处理器在大部分时间里都处于等待其他资源的状态,就必须使用一些手段去把处理器的运算能力压榨出来。否则就会造成很大的浪费,让计算机同时处理几项任务则是最容易想到的、也证明是非常有效的压榨手段。

衡量一个服务性能的高低好坏,每秒事务处理数(TPS)是最重要的的指标之一,它代表这一秒内服务端平均能响应的请求总数。
而TPS值与程序的并发能力又有非常密切的关系。

对于计算量相同的任务,程序线程并发协调得越有条不紊,效率自然越高。反之,线程之间频繁阻塞甚至思索,将会大大降低程序的并发能力。

由于计算机的存储设别与处理器的运算速度之间有着几个数量级的差距,所以现代计算机系统不得不加入一层读写速度尽可能接近处理器运算速度的告诉缓存(Cache)来作为内存与处理器之间的缓冲。

将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存中,这样处理器就无需等待缓慢的内存读写了。

基于高速缓存的存储交互很好的解决了处理器与内存的速度矛盾,但是也引入了新的问题:缓存一致性?

在多处理系统中,每个处理器都有自己的高速缓存,而他们又共享同一主内存(Main Memory),如图所示:
这里写图片描述
那么问题来了,当多个处理器的运算任务都涉及同一块主内存区域时,将可能导致自己各自的缓存数据不一致的情况,如果真的发生生这种情况,那同步回主内存的时候以谁的数据为基准呢?

为了解决此问题,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议来进行操作,这类协议有MSI 、MESI
MSOSI Synapse、Firefly 及Dragon Protocol等等。

然而,除此之外,为了使处理内存内部的运算单元尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会计算之后将乱序的结果进行重组,保证该结果与顺序执行的结果是一致的。

Java的虚拟机的即时编译器中也有类似的指令重排序优化。

了解了计算机的主存和高速缓存的关系之后,我们来了解一下java的内存模型:

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。

Java内存模型规定了所有的变量都存储在主内存中(Main memory)中。每条线程都有自己的工作内存(可与前面讲的高速缓存做类比),线程的工作内存中保存了该线程使用到的变量的主内存的副本拷贝。

线程对变量的所有操作(读取,赋值等),都必须在工作内存中进行,而不能直接读写主内存中的变量。
不同线程之间也无法直接访问对方内存中的变量,线程间变量值的传递均需要主内存来完成,线程,主内存,工作内存三者之间的交互关系如图所示:

这里写图片描述

从更低层次来说,主内存就是硬件的内存,而为了更好的运行速度,虚拟机及硬件系统可能会让工作内存优先存储于寄存器和告诉缓存中。

内存间交互操作:
一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存之类的实现细节,java内存模型定义了以下8中操作来完成。
以下8中操作来完成。
·lock(锁定):
·ulock(解锁)
·read(读取)
·load(载入)
·use(使用)
·assign(赋值)
·store(存储)
·write(写入)

后续的更新文章会接着介绍后面的内容,敬请期待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anguser

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值