volatile、synchronized、final 这些关键字分别可以解决哪些线程的安全性问题呢?
- volatile 可以解决可见性、有序性的问题
- synchronized 可以解决可见性、原子性、有序性的问题(synchronized 是全能型关键字)
- final 可以解决可见性问题
线程安全
多条线程同时工作的情况下,通过运用线程锁,原子操作等方法避免多条线程因为同时访问同一快内存造成的数据错误或冲突。原子性
解决的是某一操作不会被线程调度机制打断,中间不会有任何context switch (切 换到另一个线程)。即保证当前为原子操作。原子性与线程安全的理解
- 对于基本数据类型的“简单操作”,除了 long 与 double 外都具有原子性。因为 long 与 double 的读取和写入被 Jvm 分离成 2个slot 操作来进行,可以使用 volatile 来保证简单的赋值与返回操作的原子性。这是 volatile 的特殊用法,其基本用法是保证可见性和有序性。
- 原子类扩展了“简单操作”的范围,增加对额外一些操作的原子性。
- 原子操作并不能确保线程安全,虽然保证部分操作的原子性,但是对于大部分情况下仍然需要同步控制。
有序性
解决的是 cpu 进行指令重排序可见性
解决的是工作内存/寄存器 对主存的不可见
八种原子操作
lock(锁定):作用于主内存中的变量,它把一个变量标识为一个线程独占的状态;
unlock(解锁):作用于主内存中的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便后面的load动作使用;
load(载入):作用于工作内存中的变量,它把read操作从主内存中得到的变量值放入工作内存中的变量副本
use(使用):作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作;
assign(赋值):作用于工作内存中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作;
store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送给主内存中以便随后的write操作使用;
write(操作):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。
