深解JVM 4-JMM内存模型

Java内存模型(Java Memory Model, JMM)。

Java内存模型是围绕着并发编程中原子性、可见性、有序性这三个特征来建立的。

原子性-Atomicity

一个操作不能被打断,要么全部执行完毕,要么不执行。在这点上有点类似于事务操作,要么全部执行成功,要么回退到执行该操作之前的状态。

可见性

一个线程对共享变量做了修改之后,其他的线程立即能够看到(感知到)该变量的这种修改(变化)。

有序性

对于一个线程的代码而言,我们总是以为代码的执行是从前往后的,依次执行的。这么说不能说完全不对,在单线程程序里,确实会这样执行;但是在多线程并发时,程序的执行就有可能出现乱序。

用一句话可以总结为:在本线程内观察,操作都是有序的;如果在一个线程中观察另外一个线程,所有的操作都是无序的。前半句是指“线程内表现为串行语义(WithIn Thread As-if-Serial Semantics)”,后半句是指“指令重排”现象和“工作内存和主内存同步延迟”现象。

 

关键词synchronized与volatile总结
synchronized的特点
一个线程执行互斥代码过程如下:

1、获得同步锁;
2、清空工作内存;
3、从主内存拷贝对象副本到工作内存;
4、执行代码(计算或者输出等);
5、刷新主内存数据;
6、释放同步锁。
所以,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。

volatile是第二种Java多线程同步的手段,根据JLS的说法,一个变量可以被volatile修饰,在这种情况下内存模型确保所有线程可以看到一致的变量值

    class Test {  
        static volatile int i = 0, j = 0;  
        static void one() {  
            i++;  
            j++;  
        }  
        static void two() {  
            System.out.println("i=" + i + " j=" + j);  
        }  
    }  


加上volatile可以将共享变量i和j的改变直接响应到主内存中,这样保证了i和j的值可以保持一致,然而我们不能保证执行two方法的线程是在i和j执行到什么程度获取到的,所以volatile可以保证内存可见性,不能保证并发有序性(不具有原子性)
如果没有volatile,则代码执行过程如下:

1、将变量i从主内存拷贝到工作内存;
2、刷新主内存数据;
3、改变i的值;
4、将变量j从主内存拷贝到工作内存;
5、刷新主内存数据;
6、改变j的值;

重排序
在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:

1、编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
2、指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
3、内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

(37条消息) JMM概述_牧竹子的博客-CSDN博客_jmm

 

posted @ 2022-05-31 03:15  chch213  阅读(58)  评论(0编辑  收藏  举报