公平锁FairSync
公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取锁就会失败,并且会加入阻塞队列
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
// tryAcquire实现
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // private volatile int state;
if (c == 0) { //锁未被占用
//先判断等待队列是否是空 或者等待队列的第一个等待线程正好是当前线程
//再使用CAS外加stateOffset来占用锁
//设置锁的拥有者是当前线程
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;
}
}
不是空队列,或者不是头节点的下一个元素
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
非公平锁NonfairSync
非公平锁获取锁时不会判断阻塞队列是否有线程再等待,所以对于已经在等待的线程来说是不公平的,但如果是因为其它原因没有竞争到锁,它也会加入阻塞队列
进入阻塞队列的线程,竞争锁时都是公平的,应为队列为先进先出(FIFO)
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))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //锁未被占用
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//锁被当前线程占用
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires; //可重入
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
ReentranLock和synchronize的区别
ReetrantLock功能更丰富,具有可响应中断,可轮询尝试,公平锁等特点,synchronized是不可以响应中断的;
ReentrantLock通过Condition可以绑定多个条件;
ReetrantLock需要捕获异常,在finnally中释放锁,synchronized自动释放锁;
底层实现不一样,synchronized是同步阻塞,使用的是悲观并发策略,lock是同步非阻塞,采用的是乐观并发策略;