前言

Java语言中有许多原生线程安全的数据结构,比如ArrayBlockingQueue、CopyOnWriteArrayList、LinkedBlockingQueue,它们线程安全的实现方式并非通过synchronized关键字,而是通过java.util.concurrent.locks.ReentrantLock来实现。 刚好对这个很感兴趣, 因此写一篇博客详细分析此 “可重入锁实现原理”。

ReentrantLock(默认非公平锁)的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的。 其可重入性是基于Thread.currentThread()实现的: 如果当前线程已经获得了执行序列中的锁, 那执行序列之后的所有方法都可以获得这个锁。

公平锁

(公平锁就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己。)

公平和非公平锁的队列都基于锁内部维护的一个双向链表,表结点Node的值就是每一个请求当前锁的线程。公平锁则在于每次都是依次从队首取值。

锁的实现方式是基于如下几点:

表结点Node和状态state的volatile关键字。

sum.misc.Unsafe.compareAndSet的原子操作(见附录)。

非公平锁

(非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。)

在等待锁的过程中, 如果有任意新的线程妄图获取锁,都是有很大的几率直接获取到锁的。

ReentrantLock锁都不会使得线程中断,除非开发者自己设置了中断位。 

ReentrantLock获取锁里面有看似自旋的代码,但是它不是自旋锁。 

ReentrantLock公平与非公平锁都是属于排它锁。