一、线程安全性
1.Java内存模型中的可见性、原子性、有序性。
(1)可见性:一个线程修改的状态对另一个线程是可见的;
(2)原子性:同一时刻只有一个线程可以对它进行操作;
(3)有序性:保证线程之间操作的有序性。
二、volatile关键字
1.jvm内存模型
(1)普通变量:每个线程先从内存拷贝变量到CPU缓存中,如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。
(2)volatile 变量:JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。
2.解释什么是volatile关键字?(作用:保证内存可见性+防止指令重排)
(1)volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性。简单来说就是:volatile变量是用来确保将变量的更新操作通知到其他线程。
(2)如果一个变量加了volatile关键字,就会告诉编译器和JVM的内存模型:这个变量是对所有线程共享的、可见的。当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。
3.内存屏障和指令重排序?
(1)内存屏障:有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障。
//详解java内存屏障 https://blog.csdn.net/Michaeles/article/details/86633805
(2)指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。
//happen-before原则 https://blog.csdn.net/Michaeles/article/details/86634493
4.volatile 性能?
volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
5.volatile关键字的如何保证内存可见性?
volatile是通过内存屏障和禁止指令重排序来保证内存可见性的。每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本。
6.volatile关键字为什么只能确保可见性、不能保证原子性?
原因是声明为volatile的简单变量如果当前值与该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:“count++”、“count =count+1”。
三、volatile 变量和 atomic 变量有什么不同?
1.volatile为什么没有原子性?
2.atomic 变量为什么具有原子性和可见性?