JVM第三期(内存模型)

内存模型:

1、硬件内存模型:

在多个CPU同时访问和修改同一数据时,会遵循CPU的缓存一致性原则。

从一开始的硬件内存模型,再到后面的程序语言的发展,一只发展到语言层面的内存模型。让程序语言有自己的专属内存模型。

2、Java内存模型:

线程通过计算机指令对内存数据进行读写等操作!

基本的指令:

​ 1.主内存:lock(锁定)、unlock(解锁)、write(写入)、read(读取)

​ 2.工作内存:load(加载)、use(使用)、assign(赋值)、store(存储)

具体步骤:

​ 在线程A将x=1的共享变量加载进内存,先将x标记为独占状态,即加锁lock,然后assign和store对x=1进行赋值和存储操作,将x在内存中由1修改为2,存储到内存中,然后通过write将数据写进主存中,最后去释放x的锁定状态unlock。

​ 在A对数据x进行操作完,B线程开始对x进行操作一系列操作。

​ 上述的步骤是在多线程的理想情况下的数据操作方式,在实际情况下,一般都是同时读取x的副本到缓存中,在线程A修改完x的值后,B的缓存中x的值还是之前读取的x的副本x=1,所以对后面的操作来说,违背了数据的可见性问题和原子性问题。

在线程操作数据时一般会出现上述的问题:

可见性问题:在A线程操作完数据之后,要让其他线程知道被修改的数据的相关操作。详细来说就是在线程A操作完数据后,将数据重新 刷新进内存。

``

package com.jmh.ppp;
/*
    PACKAGE_NAME:com.jmh.ppp
    USER:18413
    DATE:2021/10/8 9:51
    PROJECT_NAME:RabbitMq
    面向代码面向君,不负代码不负卿————蒋明辉 */


public class TestJVM {
    static int a=1;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(a!=2){

                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                a=2;
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

​ 上面的代码问题,在线程1执行时,线程1会一直执行下去,线程休眠后,线程2开始执行,将a的值修改为2,此时,线程1并不会跳出循环而是会一直执行下去。

​ 解决方案1:使用volataile关键字修饰变量,修饰完的变量总是会主动加载进主内存。

​ 解决方案2:使用synchronized同步,底层去使用lock和unlock方法去对数据进行操作。

``

package com.jmh.ppp;
/*
    PACKAGE_NAME:com.jmh.ppp
    USER:18413
    DATE:2021/10/8 9:51
    PROJECT_NAME:RabbitMq
    面向代码面向君,不负代码不负卿————蒋明辉 */


public class TestJVM {
    static int a=1;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(a!=2){
                    synchronized (this){
                        int b=a+1;
                    }
                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                a=2;
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

​ 也有可能是CPU的指令重排,导致的程序的顺序执行问题。

​ 解决方案1:volataile关键字,禁止指令重排。

​ 解决方案2:synchronize线程同步。

package com.jmh.ppp;
/*
    PACKAGE_NAME:com.jmh.ppp
    USER:18413
    DATE:2021/10/8 9:51
    PROJECT_NAME:RabbitMq
    面向代码面向君,不负代码不负卿————蒋明辉 */


public class TestJVM {
    static int a=1;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(a!=2){
                    synchronized (this){
                        int b=a+1;
                    }
                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                a=2;
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

​ 这里面就得提到happens-before原则:对于两个操作A和B,这两个操作是在不同的线程中执行的,如果线程A happens-before 线程B(A优先于B执行),name可以保证,A的操作相对B的操作时可见的。下面是happens-before原则的几个规则(加粗表示重点掌握):

1.程序顺序规则:无论是否重排,与顺序执行的结果一致

2.锁定规则:对一个锁的解锁,happens-before这个锁的加锁

package com.jmh.ppp;
/*
    PACKAGE_NAME:com.jmh.ppp
    USER:18413
    DATE:2021/10/8 10:48
    PROJECT_NAME:RabbitMq
    面向代码面向君,不负代码不负卿————蒋明辉 */


public class Test01 {
    private int value=1;
    public synchronized void setValue(int value){
        this.value=value;
    }
    public synchronized int getValue(){
        return value;
    }
}

3.volatile变量规则

​ 4.线程启动规则

​ 5.线程结束规则

​ 6.中断规则

​ 7.终结器规则

​ 8.传递性规则

有序性问题:

原子性问题:一个操作时不可中断的,要么全部成功,要么全部失败。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值