- 什么是ReentrantLock 及其作用
- 可重入性
- 公平锁 & 非公平锁
- Lock接口定义
- RTL三个核心内部类Sync & NonfairSync & FairSync
- Sync
- NonfairSync
- FairSync
- RTL 的构造函数
ReentrantLock 基于 AQS(AbstractQueuedSynchronized),在并发编程中它可以实现公平锁和非公平锁来对资源进行同步,同时和synchronized一样,ReentrantLock支持可重入。ReentrantLock在调度上更灵活,支持更多丰富的功能。
可重入性在并发编程中可重入性指的是 单个线程重新进入同一个子程序仍然是线程安全的 。一个线程可以不用释放而重复获取某个锁n次,只是在释放时需要相应释放n次。
死锁:若A线程既获取了锁,又在等待自己释放锁就会造成死锁。
- 非公平锁:不按照请求锁的顺序分配,不一定拥有获取锁的机会,但性能可能比公平锁高。
- 公平锁:按照请求锁的顺序分配,拥有锁的机会稳定,但性能可能比非公平锁低。
RTL 实现了Lock接口,而Lock定义了6个方法,这6个方法定义了一些广泛的 *** 作边界。
- void Lock()方法:获取锁,加入当前锁被其他线程占用,则等待直到获取为止。
- void lockInteruptibly() throws InterruptedException;方法:获取锁,假如当前线程在等待锁的过程中被中断,那么会退出等待,并抛出中断异常。
- boolean tryLock(); 尝试获取锁,并立即返回,返回值代表的是是否成功获取到锁。
- boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 在一段时间内尝试获取锁,假如期间被中断,则抛出中断异常。
- void unlock(); 释放锁。
- Condition newCondition(); 新建一个绑定在当前Lock上的Condition对象。
Conditon对象,表示一个等待状态, 获得锁的线程在某些时刻需要等待一些条件的完成才能继续执行,可以通过await()方法注册在Condition上进行等待,然后通过Condition方法的signal()方法将其唤醒。一个Lock对象可以关联多个Condition,多个线程可以被绑定到不同的Condition上,就可以分组唤醒。Condition还提供了和限时/中断相关的功能,丰富了线程的调度策略。
abstract static class Sync extends AbstractQueuedSynchronizer {...}
- RTL内部类Sync继承了AQS,说明AQS中所有预设的机制Sync都可以使用.
- abstract 修饰Sync内部类,说明Sync需要通过其子类来进行实例化。NonfairSync和FairSync是Sync唯二的两个子类。
非公平锁的具体实现
- NonfairSync的具体实现中,Lock()方法内上来直接插队,先进行两次非公平的获取锁,若这两次获取锁失败,那么将进入FIFO队列进行排队直到获取锁。
- 而tryAquire方法则是进行一次插队尝试获取锁,如果确实不想排队,那么上层可以写个循环不断调用这个方法尝试插队获取锁。
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }FairSync
公平锁的具体实现
- lock()方法直接调用AQS的acquire()方法
- tryAcquire()实现AQS接口,若当前线程已经获取锁,则对state值进行累加 *** 作,可以继续使用锁,实现可重入。若锁一开始是空闲的,那么允许直接拿锁,若不空闲判断累加或者直接入队排号。
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }RTL 的构造函数
ReentrantLock有两个构造函数
- 默认无参构造函数使用了非公平锁的模式
- 含参构造函数 可以自由选择使用公平锁还是非公平锁实现。
- 一旦初始化就不能更改。因为RTL的属性Sync使用final修饰,一旦初始化就不可修改引用。
private final Sync sync; // 私有变量使用final修饰 public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)