java高并发程序设计(三),内存模型和线程安全

148 阅读2分钟

原子性

指一个操作是不可被中断,不可分割的。即使是在多个线程一起执行的时候,一个操作 一旦开始,就不会被其它线程干扰。

有序性

在并发时,程序执行可能出现乱序。

计算机在执行你的代码的时候不一定是按照你的代码顺序来执行的。



CPU处理指令的时候类似于流水线,如果每个步骤都占用一个资源,多个指令同时执行的时候,CPU在处理完第一个指令IF步骤的后马上执行第二个指令的IF,这样在第一个指令5个步骤执行完毕后第5个指令就已经开始执行了。

示例:



因为进行运算指令时,需要用到C的值,需要在MEM步骤后才能访问到,所以3排和倒数第二排有个×;

因为ID步骤被占用,所以4,5,最后一排有×。

优化:

有×的情况下会影响性能,所以可以在当前线程中不影响逻辑的情况下可以进行指令顺序的调换,适当的进行优化,避免×的产生。


优化后没有×:


可见性


不同的cpu都有自己的寄存器,都有自己的cache(缓存区),一个变量可能被不同的CPU,不同的寄存器,不同的cache给缓存住,也就不能保证他们的之间一定是一致的会引发可见性问题。

CPU在进行多次变量读写时,由于系统的优化,认为之前的读写操作是没必要的,往内存写的时候会直接忽略掉之前的所有操作,直接写该变量的最终结果,  导致其它线程看不见所有的操作,引发可见性问题。

多核cpu之间会有一些数据一致性的协议,但还是比较松散,无法完全保证没有可见性问题。

要保证可见性问题,就必须有性能上的代价。

使用volatile修饰符修饰变量可以防止编译器对代码进行优化而被省略,且要求每次读值。

Heppen-Before规则


线程安全的概念


指做个线程访问并处理同一个局部变量,因为该变量被不同线程处理覆盖,导致该变量出现不可预测的错误,达不到预期的结果,就会出现线程安全问题。