什么是原子性、可见性、有序性?
原子性:
原子性指的是一个操作不会被中断,操作不会受到其他线程的影响。两个线程同时对一个变量赋值,则该值要么是1要么是2,线程A和线程B互不干扰,不会被中断。
要知道基本数据类型中六种类型的读写操作都是原子操作(byte short int float char boolean ),long double 因为是64位的,以此在32位的虚拟机要进行两次读取,不是原子操作,但是现在的虚拟机大部分是64位的,long double 类型的读写也是原子操作
可见性:
可见性指的是一个线程修改共享变量的值,其他线程能够马上得到这个修改的值。
工作内存和主内存之间就会产生可见性问题,当一个线程修改某个主内存中的共享变量的时候,线程会拷贝一个变量的副本存放到工作内存中,线程对这个变量已经做出了修改,但是还没有刷新到内存中,其他线程从内存中读取该变量的值时候,看不见线程对共享变量做出的修改,指令重排序的编译器优化重排序,处理器的指令并行重排序,处理器的内存系统重排序可能会造成可见性的影响
有序性:
有序性指的是单线程中代码的执行总是按照循序执行的,多线程中可能出现乱序顺序,程序编译成字节码指令的时候可能会出现重排序现象,重排后的指令与原指令的顺序比一定一致。另一种角度:在一个线程内所有的操作都是有序的,但是在多线程下,一个线程观察另一个线程,所有的操作都是无序的,因为可能存在指令重排序和工作内存和主内存的同步延迟。编译器和处理器的重排序有编译器优化重排序,指令级并行重排序,内存系统的重排序
java内存模型解决原子性、可见性、有序性
原子性问题基本数据类型的变量的读写操作已经自动保证原子性,使用synchronized或者是ReentrantLock保证方法(静态方法,实例方法)和代码块的原子性。工作内存和主内存之间的同步延迟造成的可见性问题使用synchrozied和volatile解决,能够使得在一个线程中修改的变量立即对其他线程可见,指令重排序带来的可见性问题,编译器优化重排序java内存模型的编译器重排序规则会禁止特定类型的重排序,指令并行重排序和内存系统的重排序java内存模型的处理器重排序规则要求编译器在生成指令序列的时候,插入特定类型的内存屏障指令通过内存屏障指令来禁止特定类型的重排序。对于重排序问题,使用volatile,编译器重排序规则和处理器重排序规则来解决,同时happens-before规则也保证多线程环境下两个操作之间的原子性,可见性,有序性