李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
【转载】ReentrantLock和synchronized的比较
Leefs
2020-03-01 PM
1792℃
0条
# 【转载】ReentrantLock和synchronized的比较 ReentrantLock和synchronized的比较。Monitor是原理和作用 > **开始** 今天,我们来聊聊ReentrantLock和synchronized的相似与不同。 > 都是阻塞 ReentrantLock和synchronized都是加锁式同步,当一个线程获取了对象锁后,其它要进入同步块的线程就必须阻塞在同步块外等待。线程的阻塞和唤醒需要操作系统在用户态和内核态之间切换,所以,ReentrantLock和synchronized都是代价比较高的。 > 实现方式 synchronized是java语言的关键字,它的锁机制是由jvm实现的,是原生语法层面上的互斥,最底层是mutex。而ReentrantLock则是JDK1.5之后,提供的api层面的锁,需要在代码中显示调用lock、unlock等方法来完成。 所以,从便利性来说,synchronized使用起来更简单一些。但是从灵活度来说,ReentrantLock更灵活,可控性也更强,可实现更细粒度的锁。但是,在使用ReentrantLock时,一定要注意lock和unlock的匹配和顺序,否则就可能造成死锁。常见的方案是把unlock放在异常处理的finally语句块中。 > **性能** 人们很容易被大众化的观点所误导,认为synchronized的效率会比ReentrantLock差很多。但是事实上,synchronized在JDK的发展过程中,经过了不断优化,比如引入了偏向锁,轻量级锁,锁升级机制等,目前,已经和ReentrantLock的效率相差不多了。如果没有特殊的场景,推荐使用synchronized,因为它使用起来比较简单,且不会造成死锁。 > **是否公平锁** 排队等厕所,厕所门上有把锁。里面的人用完出来,把钥匙给队伍最前面的人,这就是公平锁。如果里面的人用完出来,把钥匙直接扔地上,谁抢上算谁的,这就是非公平锁。 **synchronized是非公平锁,并且它无法实现公平锁。要实现公平锁,可以通过ReentrantLock来实现。通过new ReentrantLock(true)可以用来构造一个公平锁。** > **是否可重入锁** 一个线程可以对某个资源重复加锁,称之为可重入锁。这个情形很常见于递归。如果锁不可重入,就有可能会发生如下情况: A线程获取方法B的锁,在方法B中,有代码递归调用了自己。于是,A线程需要在方法B中再次获取B的锁。如果锁不可重入,A就会发现,方法B上已经有锁,A就进入了等待。但事实上,给B加锁的就是A自己。自己一直在等待自己,岂不是可笑? synchronized就是一把可重入锁。当然了,使用ReentrantLock也可以实现可重入锁。 > **Monitor** ![40.ReentrantLock和synchronized的比较01.jpeg][1] 上图是一个同步块在执行时的基本示意图。**单位时间里,只能有一个线程在同步块中。**那么,一个线程在获得了同步块的执行权(即锁)之后,是否能够一直执行到线程完毕呢?我们说,可能不行。因为对某个资源的锁是有一个优先级的。正在执行的线程可能需要让位给优先级更高的线程,此时,当前线程就会进入等待区。所以,上图的,我们发现,有两块区域都是为等待的线程设置的,一个是Entry Set,另一个是Wait Set。假设当前同步块有代码正在运行,那么,新进入的线程就会进入Entry Set,被挤占被迫等待的线程,则会进入Wait Set。 图中还有一个含义是,当同步块中的线程执行完毕,退出同步块后,**Entry Set和Wait Set中的线程会共同竞争,以获得同步块的执行权,即获取锁**。 **Monitor,直译为监视器,底层实现是Mutex。**JVM会给每个对象和class字节码设置一个monitor。当某个线程要进入某个同步块是,就需要获得对应目标的monitor。换句话,当某个线程获得了对应目标的monitor,它就进入了同步块。当该线程执行完同步块,或被挤占而等待时,就会让出monito。 synchronized就是利用monitor来实现的。 > **等待可中断** 等待可中断是使用ReentrantLock时,可以实现的一个机制。当某个线程等待锁过长时间时,程序可以通过lockInterruptibly方法来使当前线程中断等待,转去执行其它的线程。 > **线程分组唤醒** 有些场景下,我们可能不希望唤醒所有的线程,而是唤醒部分线程。这种方式在synchronized下是无法实现的。但是,ReentrantLock通过提供一个Contition类,可以同时绑定多个对象,以此,来实现线程的分组唤醒。 *附:原文链接地址https://baijiahao.baidu.com/s?id=1638104862611986445&wfr=spider&for=pc* [1]: https://lilinchao.com/usr/uploads/2020/03/2801482381.jpeg
标签:
并发编程
,
锁
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/667.html
上一篇
线程通信之传统版生产者消费者模式
下一篇
线程池简单介绍
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Quartz
Spring
MySQL
Ubuntu
SpringCloudAlibaba
SQL练习题
Java编程思想
并发编程
递归
Hive
Java阻塞队列
数据结构和算法
JVM
Typora
Stream流
Kafka
Spark Streaming
Elasticsearch
算法
gorm
Git
Elastisearch
Spark SQL
HDFS
容器深入研究
JavaScript
GET和POST
人工智能
正则表达式
SpringCloud
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭