线程安全

出现线程安全的原因:

cpu、内存、I/O设备处理速度有很大的差异,为了平衡三者的速度差异,最大化的利用cpu提升性能,从硬件、操作系统、编译器等方面做了很多的优化,性能提高的同时,也产生了线程安全问题。
1.CPU增加了高速缓存
2.操作系统增加了进程、线程。通过CPU的时间片切换最大化的提升CPU的使用率
3.编译器的指令优化,更合理的利用好CPU的高速缓存

高速缓存

产生的问题:
缓存一致性问题
Cpu处理过程:先将计算需要用到的数据缓存在CPU高速缓存中,在cpu进行计算时,直接从高速缓存中读取数据并且在计算完成之后写入的缓存中。在整个过程完成后,再把缓存中的数据同步到主内存,此时会出现缓存不一致的问题,即可见性问题
解决方案

Cpu层面

1.总线锁
多个cpu下,其中一个处理器访问共享资源,总线锁会锁住cpu和内存之间的通信,在锁定期间,其他处理不能操作其他内存地址的数据,开销比较大
2.缓存锁
减小了锁的保护粒度,能够保证被多个cpu缓存的同一份数据时一致的,核心机制是基于缓存一致性协议来实现的
但是缓存锁也有问题,例如cpu0要对一个在缓存中共享的变量进行写入时,首先需要发送一个失效的消息给到其他缓存了该数据的CPU.并且要等到他们的确认回执。Cpu0在这段期间处于阻塞状态。会造成资源的浪费,又进行了优化,引入了store Buffres,cpu乱序执行,或者是重排序,造成可见性问题

Java层面

引入了JMM( java Memory Model)的概念
JMM概念
可以简单的理解为对硬件模型的抽象,定义了共享内存中多线程程序读写操作的行为规范,可以解决原子性、可见性、有序性问题
原子性保障:syncronized
可见性:syncronized,volatile,final
Syncronized:线程在加锁时,先清空工作内存->在主内存中拷贝最新变量的副本到工作内存->执行完代码-》将更改后的共享变量的值刷新到主内存中-》释放互斥锁
Volatile:被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次使用之前都从主内存刷新
final
有序性::syncronized,volatile
Volatile会禁止指令重排
Syncronized保证同一时刻只允许一条线程操作

Happen before原则
保证前一个操作的结果对于后续操作是可见的,它是一种表达多个线程之间对于内存的可见性

你可能感兴趣的:(线程安全)