Java同步锁代码阅读笔记

花了点时间看了下可重入锁和读写锁的实现:

1. Sync相关:继承自AbstractQueuedSynchronizer抽象类,内部维护了一个state变量,获得一个锁的时候会将改变量置位(变量不为0的时候表示已经被其他的线程Lock了),该变量声明成volatile:
      . 由于volatile只满足可见性,不满足原子性,但是在获取锁的时候需要判断是否当前的锁被占用,如果没有被占用,就占用这个锁。 这个操作并不是原子的。 因此在实现的时候使用了
unsafe.compareAndSwapInt
方法。

2. 可重入锁包含公平锁
FairSync
和非公平锁
NonfairSync
两种:
    . 公平锁: 先判断一下是否“公平”,即当前线程是否为等待队列中的第一个(等待队列为空或者队列中的第一个为当前线程),如果通过了公平的判断,则尝试去获取获取锁
compareAndSetState

    . 非公平锁:省去了前面判断是否公平的步骤。

3.锁的占用和释放:
    . 当前线程如果没有成功获取锁,则会加入到等待队列里面,并且阻塞当前线程, 阻塞的方式使用的是
LockSupport.park
,这个操作和
Object.wait()
效果类似,但是后者会依赖于一个Object,前者则没有这个约束,直接挂起当前线程,至于效率上的区别就不知道了,我猜想差不多的(都是native方法,需要看虚拟机的实现代码才知道)
    . 锁的释放逻辑比较显而易见,最终调用
LockSupport.unpark
实现,与notify效果也类似。

4.读写锁
ReentrantReadWriteLock
:实际上定义了两种类型的锁,一种是share的,一种是排他的锁, 对于读操作来说,只有没有排他锁占用就可以了,但是对于排他锁来说,share锁和排他锁都没有占用的时候才能获取成功。
    . 读锁:多个读锁请求过来以后都可以成功,增加引用计数,释放的时候减少引用计数;
    . 写锁:和普通的可重入锁类似。


阅读心得:
1. 公平锁会多做一步公平性检查的步骤,因此要比非公平锁效率稍微低一些。但是非公平锁也有个缺点,就是有可能一个等待了许久的线程,被一个刚进来的线程先抢得了锁。 因为释放锁的操作里面,释放和唤醒下一个等待的线程并不是一个“同步” 的操作。

2. Lock和Unlock操作需要在同一个线程里面操作的,不同的线程会报错(因为等待队列是用线程来标识的,其他的线程做Unlock会导致不知道哪个线程发的释放锁请求)

3. LockSupport之前一直没用过,park和unpark作用是读了代码才知道,如果是简单的挂起线程的话,我觉得LockSupport要比wait合适。

你可能感兴趣的:(java)