Synchronized在JDK1.6之前没有锁升级,是通过重量级锁的方式来实现线程之间的一个锁的竞争的。这导致了性能的损耗。
JDK1.6之后为了平衡数据安全和性能增加了锁升级机制。简单来说,就是在确保数据安全的情况下尽量避免进入到重量级锁的状态,这样大大提升了性能。
CAS机制:CAS全称是Compare And Swap,中文意思是比较和交换。它是一种用于实现多线程编程中无锁算法的同步机制,正如中文意思它通过比较并替换内存中变量的值来保证线程安全。该机制主要有三个比较重要的值:内存值、期望值、新值。CAS机制的操作核心就是在将新值写入到内存中的时候会去比较期望值和内存值,如果相同则更新,反之则不做任何操作。CAS机制只能保证一个共享变量的原子操作,如果需要保证多个共享变量的原子操作还是需要锁。同时也会产生ABA问题,通过版本号可以解决。
Synchronized的锁升级过程:无锁-->偏向锁-->轻量级锁-->重量级锁。
无锁:
也就是没有锁。
偏向锁:
偏向锁是为了解决无竞争情况下的加锁开销而引入的机制。当一个线程访问同步块并获取锁时,会在对象头中的标记字段中记录该线程的Thread ID。以后,当相同线程再次请求获取锁时,JVM会直接判断该线程是否是之前获取锁的线程,如果是,则无需竞争,直接获得锁。偏向锁的目标是减少多线程环境下的锁竞争,提高程序性能。
轻量级锁:
轻量级锁是在有多个线程竞争同一个锁时使用的一种优化机制。当一个线程尝试获取轻量级锁时,它会将对象头中的一部分数据复制到线程的栈帧中,然后将对象头的Mark Word(标记字段)替换为指向锁记录的指针。如果其他线程也尝试获取同一个锁,它们会进入CAS自旋状态,而不是阻塞,自旋过程是为了等待持有锁的线程释放锁。如果自旋失败(达到自旋次数的上限或者持有锁的线程仍未释放锁),轻量级锁会升级为重量级锁。
重量级锁:
重量级锁是Java中最传统的锁形式,它是基于操作系统的互斥量实现的。当多个线程竞争同一个锁时,除了自旋等待外,未能获取锁的线程会被操作系统挂起(阻塞),直到持有锁的线程释放锁。重量级锁的实现包含了较为复杂的线程阻塞和唤醒机制,因此在性能上开销较大,适用于多线程竞争激烈的场景。
锁升级过程:
在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了 synchronized 锁的升级。