百天打卡计划第五天-volatile 关键字

    技术2022-07-11  65

    文章目录

    CPU Cache 模型缓存一致性 并发编程的三个重要特性原子性可见性有序性 jvm如何保证三大特性jvm与原子性jvm 与可见性jvm 与有序性 volatile 和 synchronized 的区别

    CPU Cache 模型

    本质就是CPU的处理速度和内存的访问速度差距越来越大,导致计算资源大量闲置。 所有计算机科学中的问题都能通过增加一个中间转换层来解决,cache就是中间层的存在。

    Cache的出现是为了解决CPU直接访问内存效率低下的问题,程序在运行过程中,会将运算所需的数据从主内存中复制一份到CPU Cache中,这样CPU进行计算时就可以直接对CPU Cache中的数据进行读取和写入,当运算结束之后,再将CPU Cache中的最新数据刷新到主内存中,CPU通过直接访问Cache的方式代替直接访问主内存的方式极大地提高了CPU的吞吐能力,有了CPU Cache之后,整体的CPU和主内存支架交互的架构大概如图。

    缓存一致性

    由于缓存的出现,及大地提高了CPU的吞吐能力,但是同时也引入了缓存不一致的问题,为了解决缓存不一致的问题,通常主流的处理有如下两种:

    通过总线程加锁的方式。通过缓存一致性协议。在缓存一致性协议中最出名的是Intel的MESI协议,MESI协议保证了每个缓存中使用的共享变量副本都是一致的,它的大致思想是,当CPU在操作Cache中的数据时,如果发现该变量是一个共享变量,也就是说在其他的CPU Cache中也存在一个副本,那么进行如下操作:

    1读取操作,不做任何处理只是将Cache中的数据读取到寄存器。 2写入操作,发出信号通知其他CPU将该变量的Cache line置为无效,其他CPU在进行该变量读取的时候补得不到主内存中再次获取。

    并发编程的三个重要特性

    原子性课间性一致性

    原子性

    所谓原子性是指在一次操作或者多次操作中,要么所有的操作全部得到了执行并且不会受到任何干扰而中断,要么所有操作都不执行。

    可见性

    可见性是指,当一个线程对共享变量就行了修改,name另外的线程可以立即看到修改的最新值。

    有序性

    所谓有序性是指程序代码在执行过程中的先后顺序。

    jvm如何保证三大特性

    jvm与原子性

    在java语言中,对基本数据类型的变量的读取赋值操作都是原子性的,对引用数据类型的变量读取和赋值操作也是原子性的。jvm值保证了基本读取和赋值的原子性,其他均不保证,如果想要使得某些代码片段具备原子性,需要使用synchronized关键字,或者juc中的lock。如果想要int等类型自增操作具备原子性,可以使用juc包下的原子类封装类型 java.util.concurrent.atomic.*

    volatile 关键字是不具备保证原子性的语义的。

    jvm 与可见性

    java提供了三种方式来保证可见性:

    使用关键字volatile:当一个变量被volatile修饰时,对于共享资源的读操作会直接在主内存中进行(当然也会缓存到工作内存中,当其他线程对该共享资源进行了修改,则会导致当前线程在工作内存中的共享资源失效,所以必须从主内存中再次获取 )对于共享资源的写操作是先修改工作内存,但是修改结束后会立刻将其刷新到主内存中。使用关键字synchronized:synchronized关键字能够保证同一时刻只有一个线程获得锁,然后执行同步方法,并且还会确保在锁释放之前,会将变量刷新到主内存当中。通过juc提供的显示锁Lock也能保证可见性,Lock的lock方法可以保证在同一时刻只有一个线程获得锁然后执行同步方法,并且或确保在释放锁之前会将变量的修改刷新到主内存。

    volatile 关键字具有保证可见性的语义。

    jvm 与有序性

    在java的内存模型中,运行编译器和处理器对指令进行重排序,在单线程的情况下,重排序并不会引起什么问题,但是在多线程的情况下,重排序会影响到程序的正确运行。 java提供了三种保证有序性的方式:

    使用volatile 关键字来保证有序性使用synchronized 关键字来保证有序性使用显示锁Lock来保证有序性

    volatile 关键字具有保证有序性的语义。

    volatile 和 synchronized 的区别

    使用上的区别: ◆volatile 只能修饰 实例变量或者 类变量,不能用于修饰方法以及方法参数和局部变量、常量等。 ◆synchronized 关键字不能用于对变量的修饰,只能修饰方法或者代码块。 ◆volatile 关键子修饰的变量可以为null,而synchronized 关键字修饰的同步代码块monitor对象不能为空

    对多线程中原子性的保证 ◆volatile 无法保证原子性。 ◆由于synchronized 关键字修饰的代码块具有排他的机制,所以被synchronized修饰的同步代码块是无法中途被打断的所以具有原子性。

    对可见性的保证 ◆两者均可以保证共享资源在多线程间的可见性但是机制不同 ◆synchronized 关键字借助于jvm指令 monitor enter 和monitor exit 对通过排他的方式使得同步代码块串行化,在monitor exit 时所有共享资源都会被刷到主内存中。 ◆相比synchronized 关键字volatile 使用机器指令(偏硬件)“Lock”的方式迫使其他线程工作内存中的数据失效,不得不到主内存中再次进行获取。

    对有序性的保证 ◆volatile 关键字进制jvm编译器以及处理器对其进行重新排序,所以他保证有序性。 ◆虽然synchronized 关键字锁修饰的同步方法也可以保证顺序性,但是这种顺序性是以程序的串行化执行换来的,在synchronized 关键字锁修饰的代码块中代码指令也会发生指令重排序的情况。

    Processed: 0.016, SQL: 9