并发编程--公平锁和非公平锁

    xiaoxiao2021-04-14  29

    在上一篇博客并发编程--互斥锁ReentrantLock中我们简单介绍了一下ReentrantLock,ReentrantLock提供了公平锁和非公平锁的机制,我们已经了解到ReentrantLock提供了一个FIFO线程队列,对于公平锁来说,当锁是可获取时首先让FIFO队列中的线程获取锁,当前线程需要进FIFO队列进行等待;对于非公平锁来说,当锁是可获取时,这个线程可以直接获取锁,不用在FIFO中排队等待。

    公平锁实现:

    获取锁

    final void lock() { acquire(1);//设置state为1 } //tryAcquire(arg) 尝试获取锁 //acquireQueued(addWaiter(Node.EXCLUSIVE), arg)尝试获取锁失败后将线程放到FIFO队列中 public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); //c=0时此时锁可获取 if (c == 0) { //首先判断hasQueuedPredecessors()队列首的线程是否是当前线程,不是则不作操作最后返回false if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //即使c不等于0,需要判断当前获取锁的线程是否是当前线程 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }以上代码的实现机制:当前线程是否是FIFO队列的第一个线程,如果不是当前线程则进FIFO队列,实现了公平锁,如果当前线程是FIFO队列中的第一个线程则获取锁并运行。

    非公平锁:

    final void lock() { //如果当前锁是可获取的,则当前线程直接获取锁不用进FIFO排队获取锁 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //不然,排队获取锁 acquire(1); }以上代码的实现机制:如果当前锁是可获取的则直接获取锁,不用排队,不然则需要进FIFO队列排队获取锁。

    简单来说Reentrant的实现就是依靠公平锁和非公平锁实现的。

    非公平锁源码:

    //非公平锁 static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }公平锁源码:

    //公平锁 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. */ 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; } }公平锁和非公平锁的父类是同步锁Sync,源码如下,其实FIFO和volatile变量都是在AbstractQueuedSynchronizer中实现的,AbstractQueuedSynchronizer是同步包中实现锁机制最重要的类。

    abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; abstract void lock(); 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; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }

    转载请注明原文地址: https://ju.6miu.com/read-669746.html

    最新回复(0)