- 扯皮
为什么要研究CAS,因为AQS的底层就是CAS实现的,为什么研究AQS,在AQS篇幅了。
- 原子性
顾名思义,和化学领域的原子概念一样,就是不可再拆分的物质。
在java多线程里的原子性,意思是在多线程环境下,线程安全的操作就是原子性 操作!比如:即使一个 1000行代码的方法,在方法上使用最重量级的synschonized了,那么这1000行代码也是原子性操作!和代码多少没有关系!例如下面的num++。
- JVM原子性操作
JVM内存模型规定的原子性操作有8个,read、load、use、asign、store、write、lock、unlock
就是在JVM的规定下,只有这几个操作是原子性的,不会存在多线程下不安全的情况。
除此之外,无法保证!
- num ++操作
num++ 操作是非原子操作,虽然简单的一行代码,但是在JVM里,先宽泛的 认为包含了几个步骤:
a):主内存read+load到工作内存。 b):工作内存use到cpu,cpu进行+1,然后进行asign到工作内存。
c):然后再从工作内存store+write到主内存。
即使使用了volatile,也是需要通过工作内存到主内存的过度,强制刷新到其他线程的工作内存中。也是无法保证原子性的。
该篇文章涉及到JVM内存模型等知识点,会有篇幅单独讨论。这里只简单阐述num++非原则性操作。
- CAS解读
CAS(Compare-and-Swap),即比较并替换。
白话:就是利用了java中的Unsafe类,这个类和JVM约定好了,我这个类玩的是直接和底层cpu、物理内存打交道了。不走你JVM约定的内存模型的规则了 。除此之外,都是受你JVM内存模型约束。
核心思想: 执行函数:CAS(V,E,N)
V:内存地址,就是你变量在哪了啊
E:当前我希望你的值
N:我希望把你改成的值
比如现在内存中有个变量state初始是0。
有一个线程1来了,执行CAS(变量地址,0,1)。结果就是state由0改成1了。
如果瞬间来了1000个线程呢?如何保证线程不会争抢呢?cpu指令保证的。。感觉有点玩赖了。
线程1执行完state=1了,那么剩下的999个线程呢?一看state=1了,再执行CAS(变量地址,0,1)时,执行不了了,我希望你的值是0,但是你是1啊。没达成共识,没法玩了。那就不玩了。该线程1该干嘛干嘛去吧。
在AQS中,大量的这个套路,就是for( ; ; ) 死循环+CAS操作。所以线程1接着回来再次尝试!
真正的原子性保障还是cpu指令做到的 。至于cpu如何做到的。别扯了。目前的目标就是先把CAS理论先理解下。哈哈