在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识。 下面我们以一次假想的面试过程,来深入了解下volitile关键字吧!
JVM如何读写Volatile修饰的变量的
并发编程三大特性:可见性、有序性、原子性(原子)
Volatile关键字:线程之间让值可见,两个线程之间的数据可以通信了呢?
结论:解决并发编程的可见性
Java内存模型-JMM
主内存:栈内存、堆内存 每个线程在执行中有自己的内存
主内存 缓冲区 一直度缓存区的内存
cpu也有空闲的时间,去主内存刷新一下。一个线程修改了变量,另一个线程能感知到
主内存:方法区 + 堆区 工作内存:JVM内存模型中的虚拟机栈
指令重排(优点和缺点):性能高 内存屏障: happends-before: as-if-serial语义:
有序性:
指令重排:是一种现象,因为CPU是乱序执行的,早期CPU是顺序执行的
- java层面 java层面有没有指令重排(java字节码) 没有重排
chang编译后生成的字节码文件是否一样,加或不加Volatile的情况下
idea插件:jclasslab
JVM如何知道的 属性访问的标志:Access Flag
计算深度:
- java代码层面
- java字节码
- Hotspot源码 内存屏障 lock..
- 重排
- 汇编
- CPU
DCL+ volatile
CPU是乱序执行的,但是有的代码不能乱序执行,乱序执行的话,结果就不对了。乱序执行的一种约束
老师备课一周,我们学习只用几个小时
- Hotspot层面
Volatile和synchronized对比
- 比synchronized效率高
- synchronized jdk1.8优化,效率也相对高一些
- 并不能保证多个线程共同修改running变量时所带来的不一致问题,volatile不能替代syn
- Volatile只保证可见性,不保证原子性;Syn都保证,效率低。
10个线程共同访问同一个变量,count=0
值比10000小
线程1:+100 线程2:100+1 不保证写的时候是否102
- 解决同样的问题的更高效的方法:AtomXXX类,本事方法是原子性的,但不能保证多个方法连续调用都是原子的
count++ 不具备原子性的
锁:new真正的对象,锁的内存定义在堆内存中
-
锁定某对象o,如果o的属性发生改变,不影响锁的使用,但是如果o变成另外一个对象,则锁定的对象发生改变,应该避免将锁定对象的引用变成另外的对象
-
不要以字符串常量作为锁定的对象
wait和notify区别,原理
ReetTrantLock
在java多线程中,可以使用synchronized关键字实现线程之间同步互斥,但在JDK1.5中新增加了ReentranLock类也能达到同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定、多路分支通知等功能,而且在使用上也比synchronized更加的灵活。
必须要手动释放锁