深入理解锁(1)——编程中的这些锁,你都用过吗?

  在日常的研发工作中,经常要和各种“锁”打交到。各种各样的锁概念,很容易混淆。本篇文章开始,尝试解释各种不同的锁。这是系列文章的第一篇,先写各种锁的定义、用途和优缺点,后续的章节中,详细描述各种锁的细节。

  公平所/非公平所

  公平锁和非公平锁,描述的是锁的性质。公平锁是指:请求锁资源的候选者,按照请求顺序获取锁。非公平锁是指:请求锁资源的候选者,并不能按照请求的先后顺序获取锁,有可能后请求的先获取到锁。

  最常用的sychronized关键字,是“非公平锁”。ReentrantLock,调用空构造函数实例化的,也是“非公平锁”,当然,可以在构造函数上传入“true”,构造一个公平锁。

  ReentrantLock是如何做的呢,解释清楚这个问题,定离不开AQS,但篇幅有限,AQS后续详细介绍。非公平锁实现思路:先尝试获取锁,获取不到则放到队列中排队;公平锁实现思路:不尝试获取锁,直接放到队列中排队。其实,sychronized关键字的实现也类似,这样做的好处是什么呢?高效!在调用lock的时候,可能锁资源正好空闲,尝试拿锁就拿到了。按照概率来说,存在锁竞争的情况属于少数,不排队大大提高了系统运行效率。

  可重入锁

  可重入锁是针对线程来说的,当前线程持有某个锁,再次调用lock函数,线程不会被阻塞。sychronized关键字和ReentrantLock都是可重入锁。

  可重入锁的实现原理也很简单,只需要在锁资源上,记录持有锁的线程ID。当线程尝试拿锁的时候,判断记录的线程ID是否和当前线程ID一致,如果不一致,挂起当前线程;如果一致,则继续执行。

  经常接触到的这两种锁,都是可重入锁,有不可重入锁吗?自旋锁是一种不可重入锁。

  独享锁/共享锁

  独享锁是指锁资源只能有一个持有者。共享锁是指所资源可以有多个持有者。

  多线程编程常用的sychronized关键字和ReentrantLock都是独享锁。ReadWriteLock是共享锁,可以有多个线程共享一个锁资源。

  在MySQL的设计中,有读锁、写锁的概念,读锁可以有多个事务持有,是共享锁;写锁只能有一个事务持有,是独享锁。

  自旋锁

  自旋锁是指当一个线程在获取锁的时候,如果发现其他线程已经获取,那么该线程将循环等待,直到其他线程释放锁。

  自旋锁是通过CAS(Campare And Swap)指令实现的,CAS有三个参数,分别是变量地址、原值、目标值。如果原值和变量的值不相等,赋值失败返回false;如果原值和变量的值相等,赋值成功返回true。需要特别指出的是,CAS指令是原子操作,是CPU的指令集保障的,这是CAS能够做自旋锁的关键因素。CAS指令在java的并发包里,应用广泛,AutomicInteger等对象,都是有CAS实现的。

  通过CAS实现的自旋锁,伪代码如下:

  void lock() {

  while (cas(0, current)) {

  }

  }

  void unlock() {

  cas(c, current, 0)

  }

  有没有发现一个问题:在等待锁的时候,CPU是一直在运行的,这样是否降低了系统性能呢?这个问题应该两面来看,忙等确实浪费了CPU资源;但是让出CPU资源,进行线程上下文的切换,也是比较浪费资源的。这里就有一个平衡的问题,短暂的忙等比线程切换更经济,但长时间的忙等则是不经济的。所以,用QQ账号转让自旋锁的场景,是“短操作”——加锁期间不能有IO,只允许有少量的内存操作!

  乐观锁/悲观锁

  悲观锁是指,总是以悲观的态度看待资源竞争问题,在做操作前先加锁后操作;乐观锁则是以乐观的态度看待资源竞争问题,认为只有在较少的情况下,才会出现并发问题,在写入数据是才获取锁。

  在java中,sychronized关键字和ReentrantLock都是悲观锁。分布式编程中用到的分布式锁,也是悲观锁。调用数据库select * from T for update也是悲观锁。悲观锁锁降低了系统的吞吐量,相关资源的操作,按照“串行”的方式执行。

  在Java的并发包中,应用CAS指令实现的原子类,都是乐观锁的体现。数据库编程中,用版本号解决数据的一致性问题,也是乐观锁的体现。

  其他常听到的锁

  分段锁在面试中常常被问到,是ConcurrentHashMap的具体实现;偏向锁/轻量锁/重量锁,这是在Sychronized关键字的优化中提到的概念。

  恕我知识有限,可能还有其他的锁,文中没有列全,欢迎留言评论。

  

深入理解锁(1)——编程中的这些锁,你都用过吗?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值