lock

锁一般是用来解决并发问题的。

Java中的锁

偏向锁

偏向锁主要用来优化同一线程多次申请同一个锁的竞争。

在某些情况下,大部分时间是同一个线程竞争锁资源。

例如,在创建一个线程并在线程中执行循环监听的场景下,或单线程操作一个线程安全集合时,同一线程每次都需要获取和释放锁,每次操作都会发生用户态与内核态的切换。
偏向锁的作用就是,当一个线程再次访问这个同步代码或方法时,该线程只需去对象头的 Mark Word 中去判断一下是否有偏向锁指向它的 ID,无需再进入 Monitor 去竞争对象了。

当对象被当做同步锁并有一个线程抢到了锁时,锁标志位还是 01,“是否偏向锁”标志位设置为 1,并且记录抢到锁的线程 ID,表示进入偏向锁状态。一旦出现其它线程竞争锁资源时,偏向锁就会被撤销。偏向锁的撤销需要等待全局安全点,暂停持有该锁的线程,同时检查该线程是否还在执行该方法,如果是,则升级锁,反之则被其它线程抢占。

轻量级锁

轻量级锁适用于线程交替执行同步块的场景,绝大部分的锁在整个同步周期内都不存在长时间的竞争。
轻量级锁还使用了自旋锁来避免线程用户态与内核态的频繁切换,提高了系统性能;

自旋锁

在锁竞争不激烈且锁占用时间非常短的场景下,自旋锁可以提高系统性能。

JDK1.7 开始,自旋锁默认启用,自旋次数由 JVM 设置决定。
CAS 重试操作意味着长时间地占用 CPU。

乐观锁

乐观锁,在操作共享资源时,抱着乐观的态度进行,认为可以成功地完成操作。但实际上,当多个线程同时操作一个共享资源时,只有一个线程会成功,那么失败的线程呢?它们不会像悲观锁一样在操作系统中挂起,而仅仅是返回,并且系统允许失败的线程重试,也允许自动放弃退出操作。
乐观锁相比悲观锁来说,不会带来死锁、饥饿等活性故障问题,线程间的相互影响也远远比悲观锁要小。
乐观锁没有因竞争造成的系统开销,所以在性能上也是更胜一筹。

CAS 乐观锁在高并发写大于读的场景下,大部分线程的原子操作会失败,失败后的线程将会不断重试 CAS 原子操作,这样就会导致大量线程长时间地占用 CPU 资源,给系统带来很大的性能开销。
CAS 乐观锁在平常使用时比较受限,它只能保证单个变量操作的原子性

References

[1]12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法