公平锁:按照线程等待顺序获取锁,一般将获取锁失败的线程放入等待队列中,每次从FIFO队列的队头取出线程获取锁。这种方式会造成性能低下,大量的时间花费在线程调度上。
非公平锁:不管等待顺序,每个线程获取锁的概率都是相等的,优点是提高了响应速度,不用把大量时间花费在线程调度上,而是花费在执行代码上。
公平锁的实现方式:
ReentrantLock lock=new ReentrantLock(true);//true表示获取公平锁
非公平锁的实现方式:
ReentrantLock lock=new ReentrantLock();//默认是非公平锁
ReentrantLock lock=new ReentrantLock(false);
非公平锁的实现原理:
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1)) //CAS操作将state从0置为1
setExclusiveOwnerThread(Thread.currentThread());//锁的持有者置为当前线程
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); //返回非公平所
}
}
从上面可以看出,非公锁实现方式就是:首先获取到当前线程,判断当前锁的状态是否为0,如果是,说明当前锁没有被其他线程占有,则利用CAS操作将锁的状态从0置为1成功后,将锁的持有者置为当前线程。
公平锁的实现原理:
final void lock() {
acquire(1);
}
/**
* 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)) {
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;
}
}
可以看出,公平锁的实现,就是在非公平锁的实现上,加了一层判断hasQueuedPredecessors(),该方法的大概意思是判断是否有线程等待的时间比当前线程等待时间还要久,如果有返回true,则当前线程获取锁失败,如果没有返回false,当前线程获取到锁,也就是判断当前线程是否是等待队列的队头元素,hasQueuedPredecessors()方法实现如下:
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; //队尾
Node h = head;//队头
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}