咱们的CPU、内存、I/O设备都在不断迭代,不断朝着更快的方向的努力。可是有一个核心矛盾一直存在,就是三者速度的差别。CPU和内存的速度差别能够形容为:CPU是天上一天,内存是地上一年;内存和I/0设备的速度差别就更大了,内存是天上一天,I/O设备是地上十年。缓存
在单核时代,全部线程都是在同一CPU上执行的,全部线程都是操做同一个CPU的缓存,一个线程对缓存的写,对另外一个线程来讲必定是可见的。例以下图中,线程A和线程B都是操做同一个CPU里面的缓存,因此线程A更新了变量V的值,那么线程B以后再访问变量V,获得的必定是V的最新值。 线程
多核时代,每颗CPU都有本身的缓存,这时CPU缓存与内存的数据一致性就没那么容易解决了,当多个线程在不一样的CPU上执行时,这些线程操做的是不一样的CPU缓存。 下图中,线程A操做的是CPU-1上的缓存,而线程B操做的是CPU-2上的缓存,很明显,这个时候线程A对变量V的操做对应线程B而言就不具备可见性了。 3d
直觉告诉咱们应该是2000000,但实际状况多是1000000到2000000之间的任意一个值。cdn
假设线程A和线程B同时执行,那么第一次都会讲count=0读到各自的CPU缓存里,执行完count+=1以后,各自CPU缓存里的值都是1,同时写入内存后,咱们会发现内存中是1,而不是咱们期待的2。以后因为各自的CPU缓存里都有count的值(1),两个线程都是基于CPU缓存里的count值来计算的,因此致使最终中count的值要小于2000000,。这就是缓存可见性的问题。blog
若是循环的次数更大,咱们会发现效果更明显,最终的count值差值越大,缘由是两个线程不时同时启动的,有一个时差。内存
count+=1,至少须要三条CPU指令。it
指令1:首先,须要把count变量从内存加载到CPU寄存器。 指令2:以后,在寄存器中执行+1操做。 指令3:最后,将结果写入内存(缓存机制致使的多是写入CPU缓存而不是内存) 若是线程A在指令1执行以后作线程切换,线程A和线程B按照下图的序列执行,那么咱们发现两个线程都执行了count+=1操做,获得的结果不是咱们指望的2,而是1.io
咱们潜意识里面以为 count+=1 这个操做是一个不可分割,就像原子同样,线程的切换能够发生在count+=1以前,也能够发生在count+=1以后,可是不会发生在中间。class
咱们把一个或者多个操做在CPU执行的过程当中不被中断的特性称为原子性。变量