tomcat的线程池用的任务队列 TaskQueue extends LinkedBlockingQueue<Runnable>
,可见是个阻塞队列,里边poll,take这种方法出队之前先要拿锁,源码可以看到是用的ReentrantLock , takeLock = new ReentrantLock()
是非公平锁。
ReentrantLock
是基于AQS
实现的,内部有两个内部类NonfairSync
和FairSync
,继承自Sync
,而Sync是继承自AQS
的。
我们来走读一下这两个内部类:
非公平锁实现
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1)) //尝试先来一次CAS抢锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); //没拿到就正常acquire,里边是!tryAcquire(arg) && acquireQueued
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); //里边看如果锁0,那么再来一次CAS、成功则返回true;或者锁持有者是当前线程,则重入;其他情况返回false
}
}
公平锁实现:
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1); //正常acquire,里边是!tryAcquire(arg) && acquireQueued
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && //无前序节点
compareAndSetState(0, acquires)) { //CAS
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;
}
}
总结
LinkedBlockingQueue.poll的时候如果是非公平锁,每个抢锁的线程都可以去尝试CAS先搞2把,没成功则acquireQueued。
如果是公平锁,则先要判断当前线程在同步队列里没有前序节点才可以CAS尝试1次,如果没成功则acquireQueued。
网友评论