首页 > 代码库 > 并发编程总结5-JUC-REENTRANTLOCK-3(非公平锁)

并发编程总结5-JUC-REENTRANTLOCK-3(非公平锁)

非公平锁和公平锁在获取锁的方法上,流程是一样的;区别主要表现在“尝试获取锁的机制不同”。“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待);而“非公平锁”在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁)。

一、获取非公平锁

lock()

NonfairSync类中实现

final void lock() {    if (compareAndSetState(0, 1))        setExclusiveOwnerThread(Thread.currentThread());    else        acquire(1);}

先通过compareAndSet(0, 1)来判断“锁”是不是空闲状态。是的话,“当前线程”直接获取“锁”;否则的话,调用acquire(1)获取锁。

acquire()

public final void acquire(int arg) {    if (!tryAcquire(arg) &&        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))        selfInterrupt();}

公平锁和非公平锁,只有tryAcquire()函数的实现不同;即它们尝试获取锁的机制不同。

nonfairTryAcquire()

final boolean nonfairTryAcquire(int acquires) {    // 获取“当前线程”    final Thread current = Thread.currentThread();    // 获取“锁”的状态    int c = getState();    // c=0意味着“锁没有被任何线程锁拥有”    if (c == 0) {        // 若“锁没有被任何线程锁拥有”,则通过CAS函数设置“锁”的状态为acquires。        // 同时,设置“当前线程”为锁的持有者。        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;}

(01) 如果“锁”没有被任何线程拥有,则通过CAS函数设置“锁”的状态为acquires,同时,设置“当前线程”为锁的持有者,然后返回true。
(02) 如果“锁”的持有者已经是当前线程,则将更新锁的状态即可。

二、释放非公平锁

非公平锁和公平锁在释放锁的方法和策略上是一样的。

 

总结
公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 ——

1、公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;

2、非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。

3、当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。

并发编程总结5-JUC-REENTRANTLOCK-3(非公平锁)