从零开始
互斥锁(悲观锁)
如果多个线程想要操作一个资源。我们使用互斥锁进行资源同步,但是互斥锁的同步方式是悲观的:
简单来说,就是系统会悲观的认为,如果我们不严格同步线程调用,那么一定会产生线程资源异常。
所以互斥锁将会把资源锁定,在一个线程访问此资源时阻塞其他线程,以此来达到多线程资源同步。
那么问题在于?这样虽然能保证多线程资源安全,但是如果多线程只是进行读的操作,那么这样会进行大量的线程切换,耗时严重。
甚至有些时候,哪怕是专门进行线程同步,也比线程切换耗费时间少。
CAS
那么我们可以想屁吃,比如不锁定资源,还能同步线程资源么?
那么就要用到CAS(compare and swap)说人话就是先比较再交换。
如果线程A和线程B同时访问一个资源,此时资源的值为0,那么线程A和线程B会读取这个0值作为old value(之前读的状态),假如他们都想把这个资源的值改为1,那么这两个线程的new value(目标结果状态)。如果此时,线程A分到时间片,改变资源为1,那么在线程B分到时间片访问资源,他会先比对old value和资源现在的状态,如果不一致,他会放弃修改(其实线程A访问资源时也进行了此操作,只是省略了),进行自旋(不断进行CAS操作,不会死循环默认10次可更改)。
乐观锁(无锁)
由于我们通过CAS来实现了多线程资源同步,并没有锁定资源,所以线程每次都会乐观的认为在访问过程中资源没有被修改,会主动去比较状态值(old value),这就是乐观锁(并没有用到锁,甚至可以叫无锁)。
CAS原子性和实际调用
我们仔细想CAS流程,说了这么多,他也只有比较和交换两个流程,并没有进行同步操作,那么他不还是不安全的,比如说线程A和线程B同时对资源和old value进行比对呢?
所以CAS流程首先需要保证原子性。
那么我们使用CAS的需要怎么操作:
我们需要访问unsafe对象的CAS方法:
我们继续查看CAS方法,发现他有native修饰符,代表是个本地方法,会根据不同平台调用不同的方法。(ps:native里的本地方法是用c++编写的,JVM有讲)
native会根据你cpu的架构调用不同的指令集(硬件基础知识,再进入native的本地方法,会发现具体方法体内使用了汇编语言控制硬件。至此。
=============================================================================
杂七杂八
刚学java就知道java代码实际上是跑在虚拟机JVM上的,这也是java能跨平台运行的核心原因,甚至对于虚拟机的内存结构也学习了解过几次了,但是到这次查CAS的底层才发现,还有别的语言内核也是基于JVM。
例如:Groovy,Jruby等。属于是少见多怪了。