非面试:volatile

关键字volatile

1.多线程的三个特性?
  • 原子性:指一个操作不可中断。即使是多个线程一起执行时,一个操作一旦开始,就不会被其他线程干扰。
  • 可见性:是指当一个线程修改了某一个共享变量的值,其他线程能够立即知道这个修改。
  • 有序性:在并发时,程序的执行可能会出现乱序。有序性问题的原因是程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致。
3.volatile的作用
  • 保证内存可见性(但不保证操作的原子性)。
  • 防止指令重排。
4.volatile用法
  • 当多个线程操作同一个变量时,每个线程将拥有那个变量的本地缓存拷贝,因此,当某一个线程修改了这个变量的值时,实际上修改的是它本地缓存中的变量值,而不是主内存中的变量值,而其他线程并不知道这个变量的值被改变了。为了避免这种情况,我们可以用 volatile 关键字声明这个变量,当一个变量被声明为 volatile 后,java 内存模型确保所有使用该变量的线程能看到相同的、一致的值。
5.volatile如何保证可见性?(可见性的具体实现)(重要)
  1. 使用 volatile 关键字会将修改的值立即写入主存。
  2. 使其他线程的工作内存中缓存了该内存地址的数据无效,它们再次读取这个数据时会去主存读取。
  • 如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,当CPU发现这个指令时,立即做两件事:首先将这个变量所在缓存行的数据写回到系统内存;但其他处理器缓存的还是旧值,所以为了保证缓存一致,就会实现缓存一致性协议,每个处理器会检查自己缓存的值是不是过期了,如果过期,就将当前处理器的缓存行设置成无效状态,当对这个数据进行修改操作时,会重新从系统内存中把数据读到处理器缓存里。
6.volatile如何通知其他线程有数据变化?
  • 通过缓存一致性协议:每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当对这个数据进行修改操作时,会重新从系统内存中把数据读到处理器缓存里。
7.volatile的优点和缺点?
  • volatile的好处:volatile是一种非锁机制,这种机制可以避免锁机制引起的线程上下文切换和调度问题。因此,volatile的执行成本比synchronized更低。
  • volatile的不足:使用volatile关键字,可以保证可见性,但是却不能保证原子操作
8.volatile和synchronized区别?
  1. volatile本质是告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile只能修饰变量,synchronized可以修饰变量,方法及代码块。
  3. synchronized是独占锁,会造成线程的阻塞,存在线程上下文切换和线程重新调度的开销;而volatile不需要加锁,不会造成线程的阻塞,没有上下文切换的开销,相比synchronized 更轻量级。但JDK1.6 对 Synchronized 进行了各种优化,性能显著提升。
  4. volatile能保证数据的可见性,不能保证原子性;而synchronized既能保证可见性又能保证原子性。
  5. volatile禁止了指令重排序,它标记的变量不会被编译器优化。
9.volatile为什么不能保证原子性
  • 对单个volatile变量的读写具有原子性,但类似于volatile++这种复合操作不具有原子性。
  • Java中对基本类型变量的赋值和读取是原子操作,但是像i++这样的操作就不是原子操作,因为进行了多次原子操作,比如先读取i的值,再将i+1的值赋值给i,多个原子操作加起来就不是原子操作了,所以即便是volatile具有可见性,也不能保证它修饰的变量具有原子性。
  • 例如:一个变量i被volatile修饰,两个线程想都对其进行i++操作,i++的过程可以分为三步,首先获取i的值,其次对i的值进行加1,最后将得到的新值写回到缓存中。线程A首先得到了i的初始值100,但是还没来得及修改,就阻塞了,这时线程B也得到了i的值,由于i的值未被修改,那么线程B得到的值也是100,之后B对它进行加1操作,得到101后,并且将新值写入到缓存中,再刷入主存中。这时线程A继续执行,由于线程A之前已经读取到了i的值为100,也就是说读取的这个原子操作已经结束了,所以此时A是将100这个值加1得到101,然后将值写到缓存,最后刷入主存。所以即便是volatile具有可见性,也不能保证对它修饰的变量具有原子性。
10.volatile是怎么样保证有序性的?

volatile关键字能禁止指令重排序
1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作肯定已经全部进行,且结果对后面的操作可见;在其后面的操作肯定还没进行;
2)在进行指令优化时,不能把volatile变量前面的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

11.volatile可以用在哪些地方?
  1. 与CAS结合,比如 java.util.concurrent.atomic 包下的类 AtomicInteger,里面通过volatile来修饰value,以此来保证获得的是内存中的最新值。
  2. ConcurrentHashMap 中使用 volatile 修饰 HashEntry 的 val 属性,保证了内存可见性,所以每次获取时都是最新值,因此 ConcurrentHashMap 的 get 方法不需要加锁,非常高效。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值