无锁

无锁即乐观锁,在上一篇博客中有介绍到。无锁是通过CAS实现的,线程认为共享区域总是读多于写,因此不会对共享区域加锁。而在需要对共享区域变量进行更新时,使用CAS操作。

自旋锁

自旋锁多线程访问共享区域的时间都很短,因此当一个线程获得了共享区的锁,其他线程在企图进入共享区时,不会进入阻塞状态,而是进行“自旋”的操作,即可以理解成原地循环等待。这样做的好处是,当锁被一个线程占用的时间很短的时候,自旋的操作可以省去其他线程阻塞、唤醒的开销,大大提升效率。但如果其它线程占用锁的时间很长,那么自旋的线程只会白白消耗处理器资源,而不会做任何有用的工作,反而带来性能上的浪费。
自旋的默认次数是10次,用户可以通过使用参数-XX:PreBlockSpin来更改。

偏向锁

偏向锁顾名思义会“偏向”第一个访问的线程,偏向锁的前提假设是当一个线程获取锁,后面还有大概率该线程还会需要继续持有这把锁。当同步锁只有一个线程访问时,便假设该锁之后也只有该线程会获得,因此在该线程再次进入共享区域是,不会触发同步机制。
因此当有另一个线程抢占锁时,偏向锁结束,转换为标准的轻量化锁。而需要注意的是,在第二个线程获取锁时,会先判断第一个线程是否仍然存活,如果不存活,不会升级为轻量级锁。

轻量级锁

轻量级锁的前提假设是对于绝大部分的锁,在整个同步周期内都是不存在竞争的,通过CAS操作来避免时候互斥锁的开销。当一个线程持有轻量级锁,且只有一个等待线程,则等待线程进行自旋等待。若自旋到达一定次数,或者一个持有锁、一个自旋、又来了一个试图抢占锁,则升级为重量级锁。轻量级锁详细运行机制如下:
在代码进入同步块的时候,如果此同步对象没有被锁定(锁标志位为01状态),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝。
然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后2bit)将转变为00,即表示此对象处于轻量级锁定状态。

重量级锁

当有两个及以上的线程争用同一个锁,那么轻量级锁就不再有效,要膨胀为重量级锁。synchronized是重量级锁。重量级锁意味着等待锁的线程要进入阻塞状态,而非自旋等待。

参考

https://www.cnblogs.com/pinxiong/p/13288071.html?ivk_sa=1024320u
https://segmentfault.com/q/1010000021443579?utm_source=tag-newest
http://www.360doc.com/content/20/0602/17/70282097_916085028.shtml