java多线程的ReentrantLock.lock()分为公平锁和非公平锁。
公平锁就是阻塞的线程会排队,用一个Node对象来表示一个排队的线程。每次当再次竞争锁的时候,就会按照先进先出的顺序来获取锁。
ReentrantLock.FairSync.tryAcquire(int);
/**
* 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) {
//如果当前锁没有被占用,就尝试加锁,为了公平,得通过 //hasQueuedPredecessors()方法去检查是否可以获取锁
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());
}
非公平锁,就是方法执行进来发觉当可以获取锁的时候,不去考虑队列,直接去尝试获取锁。如果不能获取到锁,从而挂起,那还是会用Node对象来表示一个排队的线程。
ReentrantLock.NonFairSync.tryAcquire(int);
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
Sync.nonfairTryAcquire(int)
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;
}
和公平锁类似,就是没有了hasQueuedPredecessors()方法。
至于公平锁和非公平锁哪个好?我就原封不动的抄《java并发编程实战》吧
我们为什么不希望所有的锁都是公平的?毕竟,公平是一种好的行为,而不公平则是一种不好的行为,对不对?当执行加锁操作时,公平性将由于再挂起线程和恢复线程是存在的开销极大而降低性能。在实际开情况中,统计上的公平行保证–确保被阻塞的线程能最终获得锁,通常已经够用了,并且实际开销也小得多。