栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JVM第三期(内存模型)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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;



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;



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;



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;



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.传递性规则

有序性问题:

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/306111.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号