Synchronized底层的锁(偏向锁,无锁,轻量级锁,重量级锁)

synchronized底层的锁大致有以下这四类:

锁状态是否为偏向锁锁标志
无锁不可偏向01
无锁可偏向101
轻量级锁00
重量级锁10

当没有开启偏向锁测试时:

一个对象如果没有被任何线程当作锁去使用,此时就是无锁状态。(01)

一个对象如果被一个线程当作锁去使用,此时就是轻量级锁状态。(00)

一个对象当作锁被一个线程持有,另外一个线程还继续去获取该锁,此时就是重量级锁状态。(10)

1.偏向锁:

大部分情况下,锁不仅仅不存在多线程竞争,而是总是由同一个线程多次获得,为了让线程获取锁的代价更低时,这才引入了偏向锁的概念。

当一个线程访问了同步锁的代码块时,会在对象头中存储当前线程的id。

后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁,而是直接比较对象头里面是否含有存储了指向当前线程的偏向锁。

如果相等表示偏向锁是偏向了当前线程的,就不需要再次尝试获取锁了。

2.无锁:

如果锁状态为偏向锁状态,有第二个线程访问这个对象出现线程竞争;(偏向锁不会主动释放锁)操作系统检测原来只有该线程的锁状态,
如果不存活;修改为无锁状态,重新指向新的线程;

public static void main(String[] args) throws InterruptedException {
		A a = new A();
		String str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//01	无锁状态
		
		new Thread(){
			public void run() {
				//把a作为锁对象
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		Thread.sleep(10);
    }
}

 从图中我们能看到value一栏中显示(01),说明此时是无锁状态

3.轻量级锁:

轻量级锁是相对于使用操作系统互斥量来实现的传统锁而言的。轻量级锁并不是用来代替重量级锁的,它是指在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。在解释轻量级锁的执行过程之前,先明白一点,轻量级锁所适应的场景是线程交替执行同步块的情况。

轻量级锁加锁:线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
CAS:(compare and swap)

a.在初始化数组的时候,通过CAS保证只会创建出一个数组对象

b.在新增数组时,两个线程算出来索引值位置都是i,新增的时候会有一个CAS的判断,只能有一个线程新增成功

如果新增失败,那么线程会继续循环,进入下一次的新增判断

public class test01 {
	
	public static void main(String[] args) throws InterruptedException {
		A a = new A();
		
		String str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//01	无锁状态
		
		new Thread(){
			public void run() {
				//把a作为锁对象
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		Thread.sleep(10);
		str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//00	轻量级锁
	}
}

 运行后能看到为轻量级锁(00)

4.重量级锁:

如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。重量级锁是依赖对象内部的monitor锁来实现的,而monitor又依赖操作系统的MutexLock(互斥锁)来实现的,所以重量级锁也被成为互斥锁。

互斥锁(sleep-waiting):lock synchronized

public static void main(String[] args) throws InterruptedException {
		A a = new A();
		
		String str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//01	无锁状态
		
		new Thread(){
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		Thread.sleep(10);
		str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//00	轻量级锁
		new Thread(){
			public void run() {
				synchronized(a) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		Thread.sleep(10);
		str = ClassLayout.parseInstance(a).toPrintable();
		System.out.println(str);//10	重量级锁
	}
}

运行后显示为重量级锁 (10)

总结:

锁状态优点缺点使用场景
偏向锁加锁解锁不需要额外的消耗如果竞争的线程多,那么会带来额外的锁消耗基本无线程争抢的时候
轻量级锁竞争的线程不会阻塞,使用自旋,提高程序响应速度如果一直不能获取锁,长时间自旋会造成cpu的消耗如果一直不能获取锁,长时间自旋会造成cpu的消耗
重量级锁线程竞争不适用cpu自旋,不会导致cpu空转消耗cpu资源线程阻塞,响应时间长很多线程竞争锁,且锁持有时间长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值