32

系统梳理一下锁

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUzNjAxODg4MQ%3D%3D&%3Bmid=2247485325&%3Bidx=1&%3Bsn=fad70990055111f09459f397233db339
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

背景

有人对Java主流锁做了下面全面的梳理。梳理的确实挺好的。但是我看到这张图,第一个感觉是:记不住。

ZfqaA3B.png!web

因为分了太多类,彼此之间没有什么联系。 做PPT可以。 如果聊天或者面试,不用纸笔的情况下,就不太好描述了。 也不利于对原理和应用的理解。

基于上述的考虑,我就自己系统的梳理一下锁,希望可以有助于大家理解和记忆,以至于最后在工作中得到很好的应用。

先说线程锁再说分布式锁。

线程锁

概述

这里说的线程锁是Java线程锁,从原理上各个语言应该都比较相似。有很多维度的划分方式,我比较建议的是从大面上分为乐观锁和悲观锁。

乐观锁主要是自旋+CAS的方式,比如JCU( java.util.concurrent ) 的原子类

悲观锁主要用synchronized关键字的隐式锁和基于AQS的显示锁。

上面三段总结如下:

JZfQJbA.png!web

悲观锁的实现原理

1>synchronized关键字

随着java版本升级,synchronized关键字虽然是用C++写的,但是原理和JCU包的ReentrantLock很相似。synchronized关键字有4种锁状态:无锁、偏向锁、轻量级锁、重量级锁。无锁类似于ReentrantLock的交替执行,没有并发,就不涉及锁;偏向锁类似于ReentrantLock的可重入的概念,使得已经获取到锁的线程可以多次获取锁;轻量级锁解决的问题是尽量避免线程切换,使用的方法也和ReentrantLock相似,是自旋+CAS的方式;重量级锁依赖于管程monitor来实现,和ReentrantLock一样都涉及用户态和内核态切换。

根据这个我们再来补充一下Java线程锁的思维导图:

YnQrEzJ.png!web

2>基于基于AQS的显示锁

基于AQS的显示锁我之前看过一些源码。 这里面比较经典的是ReentrantLock。这是可重入锁,就是同一个线程可以反复进入加锁的线程。如果想实现不可重入锁也很简单。把可重入锁对当前线程做特殊处理的部分去掉就好了。

其他JCU下locks包里的锁比如读写锁就是将锁细化成了读锁和写锁。读锁是共享锁的实现,写锁是排他锁的实现。

ReentrantLock可以使用公平锁和非公平锁两种方式,公平锁和非公平锁各自继承了AQS。区别只是非公平锁在需要加锁时先直接尝试是否可以获取锁成功,而公平锁是先看自己是否需要排队。

下面以ReentrantLock的公平锁为例来简单聊一下AQS的源码。AQS核心是实现了CLH队列。

AQS有head、tail、持有锁的线程、状态4个主要的成员变量。

利用head!=tail就是说AQS是否未被初始化来判断是否交替执行,交替执行则不用加锁;如果需要加锁则判断是否就是当前拥有锁的线程,是的话,将进入次数+1;如果不是则判断是否需要初始化AQS,需要的话先初始化一个dummy header,再将自己加入队尾,如果是队列里dummy header的指针指向的节点,则它为先自旋判断是否可以获取锁;如果不是dummy header指针指向的节点,则使用park让出cpu。当dummy header的指针指向的节点获取到锁之后,会将head指向自己,同时将自己这个Node节点的当前线程设置为空,将自己设置为dummy header,同时将原来dummy header的指针都设置为null,使得原dummy header成为一个没有引用的节点,便于垃圾回收。

根据这个我们再来补充一下Java线程锁的思维导图:

MzIFzqZ.png!web

分布式锁

不管是线程锁还是分布式锁,都实现了tryLock、lock、unlock三个方法。

tryLock的语义是非阻塞锁,尝试获取锁,成功返回true,不成功返回false;主流lock语义是阻塞锁。实现一般基于tryLock来做自旋,不成功的时候也会有像ReentrantLock一样的阻塞操作。

常见的分布式锁实现以及数据库锁的实现详见之前写的文章:《 MySQL常见6个考题在实际工作中的运用 》这里就不再赘述了。

总结

本篇文章在介绍知识点是次要的,主要是展示了总结思考的思路,希望能对读者朋友们的思考问题方法上有所帮助,仅做参考。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK