0
点赞
收藏
分享

微信扫一扫

轻量级锁的原理与实战

i奇异 2022-03-14 阅读 111

文章目录

1. 轻量级锁的核心原理

为什么复制对象头的部分信息到线程堆栈中的锁记录的Displaced Mark Word字段?
因为内置锁对象的Mark Word的结构会有所变化,Mark Word将会出现一个指向锁记录的指针,而不再存着无锁状态下的锁对象哈希码等信息,所以必须将这些信息暂存起来,供后面在锁释放时使用。


2. 代码演示

package innerlock;



import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

public class InnerLockTest {
	

	int a=1;
	
	double b=1.1;
	public static void main(String[] args) throws InterruptedException {
		System.out.println(VM.current().details());
		Object obj=new Object();
		new Thread(()->{
			synchronized (obj) {
				System.out.println("t1:"+ClassLayout.parseInstance(obj).toPrintable());
			}
			try {
				Thread.sleep(4000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		},"t1").start();
		Thread.sleep(1000);//保证t1已经离开临界区
		new Thread(()->{
			synchronized (obj) {
				System.out.println("t2:"+ClassLayout.parseInstance(obj).toPrintable());
			}
			
		},"t2").start();

}
}


在这里插入图片描述
在这里插入图片描述

上面的代码创建了两个线程,第一个线程t1获取到锁时无线程争夺资源,因此是偏向锁;当第二个线程去争夺t1持有的锁对象时,变成轻量级锁

轻量级锁的使用场景:如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。(比如上面代码,先是线程1进行加锁变成偏向锁,然后是线程2来抢占,此时线程1已经离开临界区)


3. 轻量级锁的分类

1. 普通自旋锁
当有线程来竞争锁时,抢锁线程会在原地循环等待,而不是被阻塞,直到那个占有锁的线程释放锁之后,这个抢锁线程才可以获得锁。
自旋会消耗CPU,因此不可能无休止地进行自旋,默认情况下,自旋的次数为10次,用户可以通过-XX:PreBlockSpin选项来进行更改。

2. 自适应自旋锁

  • 如果抢锁线程在同一个锁对象上之前成功获得过锁,JVM就会认为这次自旋很有可能再次成功,因此允许自旋等待持续相对更长的时间
  • 如果对于某个锁,抢锁线程很少成功获得过,那么JVM将可能减少自旋时间甚至省略自旋过程,以避免浪费处理器资源

4. 轻量级锁的膨胀

轻量级锁的优点:在多线程竞争不激烈的情况下,通过CAS机制竞争锁减少重量级锁产生的性能损耗。重量级锁使用了操作系统底层的互斥锁(MutexLock),会导致线程在用户态和核心态之间频繁切换,从而带来较大的性能损耗
轻量级锁的缺点:临界区代码执行耗时较长,在其执行期间,其他线程都在原地自旋等待,会空消耗CPU。因此,如果竞争这个同步锁的线程很多,就会有多个线程在原地等待继续空循环消耗CPU(空自旋),这会带来很大的性能损耗

在争用激烈的场景下,轻量级锁会膨胀为基于操作系统内核互斥锁实现的重量级锁


参考:《Java高并发编程卷2》 尼恩

举报

相关推荐

轻量级锁

0 条评论