怎么拥抱她终究要飞翔
1. 继承关系
Serializable
接口不必多说Lock
接口六个方法:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
思考①:
lockInterruptibly
是何方妖孽?存在意义是什么?
顾名思义就是可中断的加锁。在加锁的过程中是可能会在队列中等待的,如果此过程不能被中断,那这个线程在成功加锁之前就无法被优雅结束了。所谓优雅,就是在结束之前能做一些资源释放之类的,而不是不计后果直接kill。
那可不可以用别的方法?肯定是有,但是大体思路和中断基本是一致的。详细有一个线程在等待队列中,现在我们要取消它,那做法有两种:
- 取队列里找到它,更新队列状态
- 更新线程的状态,等它执行的时候自己做判断
显然第一种实现起来麻烦很多,第二种就简单多了,而只要采用第二种思路,就会用一个类似标志位的东西,那思路就和中断异常一致了。
思考②:
Condition
是嘛?
这属于MESA模型的概念,借用《极客时间》王宝令老师的一张图,感兴趣的小伙伴可以自己去看一下
2. 内部类
2.1 Sync
继承AQS
abstract static class Sync extends AbstractQueuedSynchronizer{。。。}
非公平方式获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 获取同步器状态,也就是加载同步器上的锁的层数,如果是0,表示锁可用
// 同步器概念约等于锁
int c = getState();
// 如果同步器状态可用,则尝试获取
if (c == 0) {
// CAS获取锁
if (compareAndSetState(0, acquires)) {
// 该方法属于AbstractOwnableSynchronizer定义的,就是设置同步器的当前
// 所属线程
setExclusiveOwnerThread(current);
return true;
}
}
// 当同步器上的锁是当前线程加上的,也就是重入的情况
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
// 可重入锁最多可以加Integer.MAX_VALUE层
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
为什么说是非公平的?
该方法在判断同步器状态为可用时就立即以CAS方式尝试获取锁,但是此时可能等待队列中存在等待节点。
尝试释放锁
protected final boolean tryRelease(int releases) {
// c为此次释放后,剩余的锁层数
int c = getState() - releases;
// 只有锁的持有线程才可以释放锁
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
// 锁彻底释放,可被再次获取
free = true;
// 清除锁的所属线程
setExclusiveOwnerThread(null);
}
setState(c);
// 只有锁彻底释放的时才是true
return free;
}
其余一些方法
// 判断锁是否由当前线程持有
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 返回与当前锁关联的condition对象
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* 从数据流中重组实例
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // 重置锁状态
}
2.2 NonfairSync
继承Sync
static final class NonfairSync extends Sync {...}
加锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
- 显然是非公平方式,先尝试获取
acquire
方法是AQS里面,尝试获取锁失败后会加如等待队列
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire
就是Sync
里面的方法
2.3 FairSync
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// 因为tryAcquire是公平的,所以acquire是公平的
final void lock() {
acquire(1);
}
// 公平方式的tryAcquire
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;
}
}
3. 构造方法
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- 默认是非公平锁
- 可以接受一个公平与否的参数
4. 加锁方法
Lock
public void lock() {
sync.lock();
}
FairSync
的Lock
直接调用的AQS
的acquire
,因为其重写了tryAcquire
,而AQS
的acquire
方法的公平性可以依赖于重写的tryAcquire
方法,所以这个方法还算是公平的NonfairSync
的Lock
方法在一开始就直接尝试获取锁了,稳稳的不公平
lockInterruptibly
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
- AQS中提供了实现,如果线程被中断,则会抛出中断异常,否则会多次自旋尝试获取锁,未果后加入等待队列
tryLock
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
tryLock无参
都是不公平的
tryLock(long timeout, TimeUnit unit)
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
- 带时间参数的
tryLock
方法公平性受tryAcquire
的影响
5. 释放锁方法
unlock
public void unlock() {
sync.release(1);
}
- 调用的是
AQS
的release
方法,其中又调用了Sync
的tryRelease
方法
6. 其它方法
// 锁的层数,就是state的值
public int getHoldCount() {
return sync.getHoldCount();
}
// 所属线程
protected Thread getOwner() {
return sync.getOwner();
}
// 是否是公平锁
public final boolean isFair() {
return sync instanceof FairSync;
}
// ~
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
7. 特殊用途的方法
// 获取等待线程,但是并不是准确的,因为线程状态是动态的
// 这个方法的目的是让子类更方便去实现一些更具扩展性的方法
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
// 获取等待在给定condition上的线程,但是并不是准确的,因为线程状态是动态的
// 这个方法的目的是让子类更方便去实现一些更具扩展性的方法
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// 返回等待线程池数的估计值,用于监控系统状态,而非线程同步
public final int getQueueLength() {
return sync.getQueueLength();
}
// 目标线程是否处于等待队列中,主要用于监控系统状态
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
// 是否有线程处于等待队列中,主要用于监控系统状态
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
// 在目标condition上是否有等待线程,主要用于监控系统状态
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// 判断这个锁是否被某个线程持有,用于监控系统状态,并不是为了同步控制
public boolean isLocked() {
return sync.isLocked();
}
// 锁是否由当前线程持有,主要用于debug和测试
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}