多线程进阶:锁优化

线程状态

介绍锁优化之前我们先来看看,线程和线程的状态。锁和线程的关系是怎样的呢,举个简单的例子你就明白了。
比如,你今天要去银行办业务,你到了银行之后,要先取一个号,然后你坐在休息区等待叫号,过段时间,广播叫到你的号码之后,会告诉你去哪个柜台办理业务,这时,你拿着你手里的号码,去到对应的柜台,找相应的柜员开始办理业务。当你办理业务的时候,这个柜台和柜台后面的柜员只能为你自己服务。当你办完业务离开之后,广播再喊其他的顾客前来办理业务。

这个例子中,每个顾客是一个**线程**。 
柜台前面的那把椅子,就是**锁**。
柜台后面的柜员,就是共享***资源***。 
你发现无法直接办理业务,要取号等待的过程叫做**阻塞**。
当你听到叫你的号码的时候,你起身去办业务,这就是**唤醒。** 
当你坐在椅子上开始办理业务的时候,你就获得**锁**。 
当你办完业务离开的时候,你就**释放锁**。

对于线程来说,一共有五种状态,分别为:初始状态(New) 、就绪状态(Runnable) 、运行状态(Running) 、阻塞状态(Blocked) 和死亡状态(Dead) 。

在这里插入图片描述

锁优化

锁优化一般是用来提高效率的策略。

以Sychronized 为例,优化操作是编译器 + JVM两者配合进行,在这里不做具体介绍了。

锁消除

编译器 + JVM会根据代码的运行情况只能判断当前的锁是否有必要,如果没有必要就直接吧锁的代码优化掉。例如:

stringBuffer.append("hello");

这行代码,因为stringBuffer是线程安全的,每次执行都会涉及加锁和解锁操作,事实上,如果stringBuffer只是在一个线程中使用,就不涉及线程安全问题。在这里加锁操作就会被优化掉。

 就好比,你去银行取钱,所有情况下都需要取号,并且等待吗?
 其实是不用的,当银行办理业务的人不多的时候,
 可能根本不需要取号,直接走到柜台前面办理业务就好了。

偏向锁

第一次尝试加锁的线程,不会真的加锁,而是进入偏向锁状态(很轻量级的标记),直到其他线程也来竞争这把锁,才会取消偏向锁状态,真正的进行加锁。

 就好比,你去银行取钱,所有情况下都需要取号,并且等待吗?
 其实是不用的,当银行办理业务的人不多的时候可能根本不需要取号,
 直接走到柜台前面办理业务就好了,但是如果后边有人来了,那就要都要取号排队。

锁消除和偏向锁的优化思路相同:就是能不加锁就不枷锁。

自旋锁

真的又来了多个线程来竞争锁的时候,偏向锁状态就会消除,此时线程使用自旋锁的方式来尝试进行获取锁。自旋锁能保证其他想竞争锁的线程尽快获取到锁,付出了一定的 CPU 资源。

自旋锁和阻塞锁最大的区别就是,到底要不要放弃处理器的执行时间。对于阻塞锁和自旋锁来说,都是要等待获得共享资源。但是阻塞锁是放弃了CPU时间,进入了等待区,等待被唤醒。而自旋锁是一直“自旋”在那里,时刻的检查共享资源是否可以被访问。
由于自旋锁只是将当前线程不停地执行循环体,不进行线程状态的改变,所以响应速度更快。但当线程数不停增加时,性能下降明显,因为每个线程都需要执行,占用CPU时间。如果线程竞争不激烈,并且保持锁的时间段。适合使用自旋锁。

锁膨胀(无奈之举,严格来说不能算作优化)

当锁竞争更加激烈的时候,此时就会从自旋锁状态膨胀为重量级锁(挂起等待锁)。

 就好比,银行排队的人很多可能你要等很久,这个时候你还不如回家打打王者或者敲敲代码,等通知

锁粗化

理解锁的“粒度”

synchronized (Demo.class) {
	for(int c = 0; c < 1000; c++){
		i++;
	}
}
for(int c = 0; c < 1000; c++){
	synchronized (Demo.class) {
		i++;
	}
}

上边两个代码,上边的写法,锁的粒度就比较粗,而下边的写法,锁的粒度就比较细。直观来说加锁状态下执行的代码越多,锁粒度就越粗,反之就越细。

锁粗化

也就是如果逻辑中,需要多次加锁解锁,并且在解锁时没有其他线程来竞争,此时就会把多组加锁操作合并在一起。

stringBuffer.append("hello");
stringBuffer.append("hello");
stringBuffer.append("hello");
stringBuffer.append("hello");

在这里插入图片描述
每次加锁解锁都有开销,粗化后就会减少加锁次数,这样效率就提高了。

锁状态转换示意图

在这里插入图片描述
更多内容可以参考《深入理解JVM》

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值