Java内存模型

2019-09-27  本文已影响0人  一如既往wfqwfq

1、概述

Java 内存模型用来屏蔽掉各种硬件和操作系统的内存差异,达到跨平台的内存访问效果。

2、主内存和工作内存

Java内存模型规定了所有的变量都存储在主内存中,此处的主内存仅仅是虚拟机内存的一部分,而虚拟机内存也仅仅是计算机物理内存的一部分(为虚拟机进程分配的那一部分)。

Java内存模型分为主内存,和工作内存。主内存是所有的线程所共享的,工作内存是每个线程自己有一个,不是共享的。

每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值),都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者之间的交互关系如下图:


image.png

3、Java内存交互

JLS定义了线程对主存的操作指令:lock,unlock,read,load,use,assign,store,write。这些行为是不可分解的原子操作,在使用上相互依赖,read-load从主内存复制变量到当前工作内存,use-assign执行代码改变共享变量值,store-write用工作内存数据刷新主存相关内容。

在将变量从主内存读取到工作内存中,必须顺序执行read、load;
要将变量从工作内存同步回主内存中,必须顺序执行store、write。

8种操作必须遵循以下规则:

1:不允许read和load、store和write操作之一单独出现。即不允许一个变量从主内存被读取了,但是工作内存不接受,或者从工作内存回写了但是主内存不接受。
2:不允许一个线程丢弃它最近的一个assign操作,即变量在工作内存被更改后必须同步改更改回主内存。
3:工作内存中的变量在没有执行过assign操作时,不允许无意义的同步回主内存。
4:在执行use前必须已执行load,在执行store前必须已执行assign。
5:一个变量在同一时刻只允许一个线程对其执行lock操作,一个线程可以对同一个变量执行多次lock,但必须执行相同次数的unlock操作才可解锁。
6:一个线程在lock一个变量的时候,将会清空工作内存中的此变量的值,执行引擎在use前必须重新read和load。
7:线程不允许unlock其他线程的lock操作。并且unlock操作必须是在本线程的lock操作之后。

8:在执行unlock之前,必须首先执行了store和write操作。

3、原子性、可见性、有序性

1.原子性

即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

int a = 10; //1
a++; //2
int b=a; //3
a = a+1; //4

上面这四个语句中只有第1个语句是原子操作,将10赋值给线程工作内存的变量a,而语句2(a++),实际上包含了三个操作:1. 读取变量a的值;2:对a进行加一的操作;3.将计算后的值再赋值给变量a,而这三个操作无法构成原子操作。对语句3,4的分析同理可得这两条语句不具备原子性。

2.可见性

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

3.有序性

在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

int a = 1;  //1
int b = 2;  //2

这两行代码无论先执行第1行还是第2行都对执行结果不会有影响,编译器可能会对它们进行重排序,可能先执行第二行在执行第1行。

public class NoVisibility{
    private static boolean ready;
    private static int number;

    private static class Reader extends Thread{
        public void run(){
        while(!ready){
            Thread.yield();
        }
        System.out.println(number);
    }
}
    public static void main(String[] args){
        new Reader().start();
        number = 42;  //1
        ready = true;  //2
    }
}

这段代码中如过重排序先执行了第2行代码,那么输出就是0,与我们预期的结果是不同的。所以重排序在多线程下可能有安全问题。

4、解决多线程下原子性、可见性、有序性问题

1. volatile关键字

解决可见性、有序性问题。

2.synchronized关键字

解决原子性、可见性、有序性问题

上一篇 下一篇

猜你喜欢

热点阅读