【并发专题】Volitale 连环炮
本问题对应的项目链接:高频题回答模版训练
说明:一般来说,这个要嘛就问的比较表面,要嘛会问的比较底层,大家至少掌握表面的部分,底层的一般会涉及操作系统了,这道题的问法也比较常规。
1、Volitale 了解吗?简单介绍一下(指导:回答它的三个作用)
2、Volitale 可见性底层实现了解不?简单说一下
3、你觉得什么样的场景下需要用到 volitale,可以你见过的一些例子吗?
本问题对应的项目链接:高频题回答模版训练
说明:一般来说,这个要嘛就问的比较表面,要嘛会问的比较底层,大家至少掌握表面的部分,底层的一般会涉及操作系统了,这道题的问法也比较常规。
1、Volitale 了解吗?简单介绍一下(指导:回答它的三个作用)
2、Volitale 可见性底层实现了解不?简单说一下
3、你觉得什么样的场景下需要用到 volitale,可以你见过的一些例子吗?
共以下 6 个回答
1、Volitale 了解吗?简单介绍一下
Volitale是java中的一个关键字,用此关键字修饰的对象将拥有两大属性
2、Volitale 可见性底层实现了解不?简单说一下
当有线程对被Volitale修饰的对象进行增删改的时候,该线程不会将结果存入自己的工作空间而是直接存入共享的内存空间,同时其他线程在读取该对象的时候,会直接从内存空间中读取。
3、你觉得什么样的场景下需要用到 volitale,可以你见过的一些例子吗?
在存在多个volitale属性修饰对象的环境下将不能保证原子性。因此当只有一个对象在程序中运行的时候适合使用,相比于synchronized性能会更好。比如在书写懒汉式的单例模式的时候,要用volitale修饰实例对象,防止在创建单例的时发生候重排序导致创建多个对象。
1、Volitale 了解吗?简单介绍一下(指导:回答它的三个作用)
volatile是java中的一个关键字,被他修饰的变量可以保证其可见性和有序性
可见性就是指对volatile变量的写操作在工作内存修改后直接写回主内存,并且使其他线程的工作内存中的变量副本失效,对volatile的读操作由于在工作内存中失效,就会去主内存中读取,所以保证了可见性。
并且通过在读写volatie变量时加入内存屏障来禁止指令重排序
2、Volitale 可见性底层实现了解不?简单说一下
底层就是在对volatile变量进行读写操作时,在汇编层面上加入一条Lock指令,在写操作时就会直接将缓存行中的内容直接写回内存,并通过总线嗅探使其他缓存有该变量的缓存行无效
3、你觉得什么样的场景下需要用到 volitale,可以你见过的一些例子吗?
比如通过双重检验锁创建单例对象时,用volatile修饰单例对象,来保证new操作时不会发生重排序。
并且像AtomicInteger中对内部的value都会使用volatie修饰,来确保得到的是主内存中最新的值再进行CAS
还有就是AQS框架中的int型同步状态state也是使用volatie修饰
1、Volitale 了解吗?简单介绍一下(指导:回答它的三个作用)
保证可见性、禁止指令重排序(举个创建对象的例子)、不保证原子性
2、Volitale 可见性底层实现了解不?简单说一下
3、你觉得什么样的场景下需要用到 volitale,可以你见过的一些例子吗?
在23种设计模式中单例模式,在使用懒汉模式实现单例模式,即只有调用到getInstance(0方式,才创建出来对象,会出现线程不安全的情况,可以使用采用双重校验机制保证线程安全之后,还是会出现多个线程时出现指令重排序的现象,就是线程p1执行(没有执行到初始化对象这一步),p2线程执行if(instancenull )语句直接返回了错误的对象, instance,还是出现了线程不安全的情况。因此,可以使用valitale关键字修饰共享变量,禁止指令重排序保证线程安全。
1.volitale是Java中一个用于修饰变量的关键字,被voilitale修饰的变量保证可见性,即读写该变量必须去共享内存中操作而不是线程的工作内存。禁止指令重排,编译的时候会对一些语句在不影响运行逻辑的情况下进行指令重排来提升工作效率,这样可能不会按照预想的逻辑运行,在使用volitale修饰后可以强制按照代码的顺序运行;
2.Java中的线程有自己的工作内存和共享内存,对于没有volitale修饰的变量,直接在自己的工作内存进行操作,如果有则需要从共享内存中读取,在自己的工作内存中操作,然后写回共享内存;
3.在线程安全的单例模式下,单例对象需要加volitale进行修饰,创建一个对象需要(1)分配空间;(2)初始化对象实例;(3)把对象指向分配的地址;没有特殊处理可能会出现指令重排,这三步不会按照顺序执行,在多线程环境下有些线程可能获取到一个空对象,出现nullPointerException
1、volatile是java的一个关键字,主要作用是保证变量的可见性、禁止指令重排序。volatile修饰的变量,保证每个线程读取的时候,只能从共享内存里面读,平时没有volatile的变量是线程从自己的工作内存里面读取的。同时读写的时候,内部的指令一定是按照程序员写的代码顺序来执行的,不会出现指令重排的情况。但是它没办法保证操作的原子性,所以不能单靠volatile保证线程安全。
2、每个java线程都有自己的工作内存,如果没有volatile修饰的变量,读取的时候,直接从自己的工作内存里面读,这个时候读到的数值,可能不是最新的,因为别的线程也有自己的工作内存,别的线程可能已经改了这个变量的值,提交到共享内存,导致多线程下这些共享变量在不同线程看来,值是不一样的。为了保证每个线程在操作共享变量的时候,看到的都是这个变量最新的值,规定只能从共享内存里面读取之后再操作
3、比如用双重检测锁的方式,写单例模式的demo,要用volatile修饰实例对象,避免指令重排序导致单例失败
1、volatile 了解吗?简单介绍一下(指导:回答它的三个作用)
volatie 用于保证所修饰变量对所有线程的可见性和顺序性。
可见性就是指当一个线程修改一个共享变量时,另外一个线程能立马读到这个修改的值。顺序性就是指对 volatile 变量的读写操作都是按顺序执行的,不会出现重排序情况。
没有原子性是因为,它只对单个 volatile 变量的读写具有原子性,如果是多个 volatile 操作或是 volatile++ 这种复合操作,整体上不保证原子性。
2、volatile 可见性底层实现了解不?简单说一下
其实就是在对 volatile 变量进行写操作的汇编代码之前,加了一条 Lock 前缀指令。这个 Lock 前缀指令在多核处理器下会将:当前处理器缓存行的数据写回到内存并使其它 CPU 里缓存了该内存地址的数据无效。后者主要是通过处理器遵循 MESI 协议来实现的,每个处理器通过嗅探总线来检查自己的数据是否过期,并做对应的处理。
3、你觉得什么样的场景下需要用到 volatile,可以你见过的一些例子吗?
volatile 基于可见性,比较适合用于标记一个状态变量。比如在多线程间控制循环或者任务的执行。当一个线程修改了 volatile 修饰的状态变量后,其他线程能立马感知并做对应的处理。
除此之外,单例模式的一种实现是利用双重检查锁定来创建对象,其中就用到了 volatile 来修饰那个单例实例,目的就在于避免 new 对象时可能出现的指令重排序,导致错误结果。这个过程主要用到了 volatile 的顺序性。