Java并发之基础理论
线程不安全分析
对共享变量进行写操作时,原子性、可见性和有序性不能同时保障,导致线程不安全,如下图所示:
反过来说,如果没有共享变量,或者只存在共享变量的读操作则不会存在线程安全问题。
原子性
定义:原子性就是指对数据的操作是一个独立的、不可分割的整体。也就是说线程A操作数据的过程中,其它线程是无法进行修改的。
非原子性原因:一条操作系统指令的执行是原子性的,但是通常Java语言层面的一次操作对应多条操作系统指令。
可见性
定义:可见性是指某个线程更改共享变量后,其它线程可以立即读取到最新值。
不可见原因:每个线程都有自己的工作内存(即CPU的高级缓存,这么做的目的还是在于进一步缩小存储系统与CPU之间速度的差异,提高性能)。如下图所示,对于共享变量,线程每次读取的是工作内存中共享变量的副本,写入的时候也直接修改工作内存中副本的值,然后在某个时间点上再将工作内存与主内存中的值进行同步。这就会导致如果线程1对某个变量进行了修改,线程2却有可能看不到线程1对共享变量所做的修改。
有序性
定义:有序性是指程序执行的顺序按照代码的先后顺序执行。
产生乱序的原因:为了提高性能,编译器和处理器可能会对指令做重排序。主要分为以下三种:
- 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
- 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
*常见解决方案
参考: