什么是Java中的公平锁?


一直想分析下公平锁和非公平锁在Java中的实现。
公平锁(Fair):加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
非公平锁(Nonfair):加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
----------------------------------------------------------------------------------------------------
首先Java中的ReentrantLock 默认的lock()方法采用的是非公平锁。
也就是不用考虑其他在排队的线程的感受,lock()的时候直接询问是否可以获取锁,而不用在队尾排队。

下面分析下公平锁的具体实现。
重点关注java.util.concurrent.locks.AbstractQueuedSynchronizer类
几乎所有locks包下的工具类锁都包含了该类的static子类,足以可见这个类在java并发锁工具类当中的地位。
这个类提供了对操作系统层面线程操作方法的封装调用,可以帮助并发设计者设计出很多优秀的API


ReentrantLock当中的lock()方法,是通过static 内部类sync来进行锁操作
public void lock() 
{
     sync.lock();
}
//定义成final型的成员变量,在构造方法中进行初始化 
private final Sync sync;
//无参数默认非公平锁
public ReentrantLock() 
{
    sync = new NonfairSync();
}
//根据参数初始化为公平锁或者非公平锁 
public ReentrantLock(boolean fair) 
{
    sync = fair ? new FairSync() : new NonfairSync();
}

-----------------------------------------明日再更--------------------------
11月11日更
介绍非公平锁
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);
        }
    }

那么调用默认构造方法构建的ReentrantLock的lock()方法的时候,其实调用的是NonfairSync对象的lock()方法,
protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,
unsafe对象是通过compareAndSwapInt方法实现的CAS操作
/** 
* 比较obj的offset处内存位置中的值和期望的值,如果相同则更新。此更新是不可中断的。 
*  
* @param obj 需要更新的对象 
* @param offset obj中整型field的偏移量 
* @param expect 希望field中存在的值 
* @param update 如果期望值expect与field的当前值相同,设置filed的值为这个新值 
* @return 如果field的值被更改返回true 
*/  
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);  


CAS操作有3个操作数,内存值M,预期值E,新值U,如果M==E,则将内存值修改为U,否则啥都不做。

于是通过上面的CAS操作,判断state变量的值,如果是0(表明该锁没有被线程占用),则可以设置state为1,占有该锁。
从这里我们就可以看到非公平锁的不公平性,后面我们会看到有一个队列的线程可能在等待该锁的释放,而新来的线程我们看到直接询问是否可以拿到锁。



https://www.zhihu.com/question/36964449/answer/71678967

猜你喜欢

转载自blog.csdn.net/varyall/article/details/80210668