现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。

在1.6之中为了提高性能,便对synchronized锁进行了优化,实现了各种锁优化技术,如:适应性自旋,锁消除,锁粗化,轻量级锁,偏向锁。

各种锁的使用场景

(偏向锁》轻量级锁》重量锁)

偏向锁:通常只有一个线程访问临界区。

轻量级锁:可以有多个线程交替进入临界区,在竞争不激烈的时候,稍微自旋就能获得锁。竞争激烈时会膨胀为重量级锁

重量级锁:线程间出现了激烈的竞争就需要使用重量级锁,此时未获取到锁的线程会进入阻塞队列,需要操作系统介入。
  jvm设置偏向锁和轻量级锁,就是为了避免阻塞,避免操作系统的介入。

引入偏向级锁是为了减少在无多线程竞争的情况下,尽量减少不必要的轻量级锁执行路径,因为轻量级锁的获取及释放依赖多次CAS原子指令,而偏向锁只需要在置换线程时,使用CAS操作把获取到这个锁的线程线程的ID记录在对象的Mark Word之中,从而减少性能消耗,不过遇到多线程竞争的情况时就必须撤销偏向锁。另外一个原因就是,在HotSpot虚拟机中,大多时候是不存在锁竞争的,常常是一个线程多次获取同一个锁,因此直接使用轻量级锁会增加很多不必要的消耗,所以可以才引入了偏向锁。

》》》轻量级锁
jdk1.6中加入的新型锁机制,它名字中的“轻量级”是相对于使用操作系统互斥量来实现的重量级锁而言的。首先需要强调的是,轻量级锁并不是来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统重量级锁使用操作系统互斥量产生的性能消耗。在解释轻量级锁的执行过程之前,先明白一点,轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁

》》》偏向锁
在jdk1.6中引入的,它的目的是消除数据无竞争情况下的同步原语,进一步提高程序的运行性能。如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除连CAS都不做。偏向锁,顾名思义,它会偏向于第一个访问它的线程,如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用锁的情况,则持有偏向锁的线程将永远是不需要在进行同步。如果运行过程中,遇到其它线程抢占资源,则持有偏向锁的线程会被挂起,jvm会消除它身上的偏向锁,将锁恢复到标准的轻量级锁。

》》》自旋锁
如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
但是线程自旋是需要消耗cup的,说白了就是让cup在做无用功,如果一直获取不到锁,那线程也不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。