JDK之ReentrantLock,AbstractQueuedSynchronizer源码分析

来源:互联网 发布:门捷列夫 知乎 编辑:程序博客网 时间:2024/06/04 17:54

ReentrantLock默认使用非公平锁

    public ReentrantLock() {        sync = new NonfairSync();    }

所谓公平锁就是先阻塞的程序先获得锁。非公平锁则有操作系统的调度系统来调度。


NonfairSync就是一个同步器

    final static 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);        }    }

而Sync则是这样实现的

    static abstract class Sync extends AbstractQueuedSynchronizer {

现在来关注下ReentrantLock的lock方法

    public void lock() {        sync.lock();    }
实际就是调用的NonFairSync的lock方法

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

而这个用的AbstractQueueSynchronizer中的方法来实现的

    protected final boolean compareAndSetState(int expect, int update) {        // See below for intrinsics setup to support this        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);    }
意思就是如果内存中的state这个字段是0,则将它置为1,否则执行acquire这个函数。注意compareAndSwapInt这句话是原子性的。所以保证只能有一个线程能成功将state置为1,从而获得锁。

同时执行

    protected final void setExclusiveOwnerThread(Thread t) {        exclusiveOwnerThread = t;    }

这个函数,置当前获得锁的函数。


那执行compareAndSetState失败的函数则执行acquire这个函数。看一下这个函数都干嘛了呢

<pre name="code" class="java">    public final void acquire(int arg) {        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    }

看一个tryAcquire这个函数

        protected final boolean tryAcquire(int acquires) {            return nonfairTryAcquire(acquires);        }

        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;        }

此时会先尝试着compareAndSetState这个函数,若又失败return false

    public final void acquire(int arg) {        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    }
那么会先执行addWaiter这个函数。这个函数就是将当前线程生成一个节点对象,然后放入队列里头

    private Node addWaiter(Node mode) {        Node node = new Node(Thread.currentThread(), mode);        // Try the fast path of enq; backup to full enq on failure        Node pred = tail;        if (pred != null) {            node.prev = pred;            if (compareAndSetTail(pred, node)) {                pred.next = node;                return node;            }        }        enq(node);        return node;    }

如果队列不是空则放在队列尾部

否则初始化一个队列

    public final void acquire(int arg) {        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    }
在看下acquireQueued都干了些什么呢

    final boolean acquireQueued(final Node node, int arg) {        try {            boolean interrupted = false;            for (;;) {                final Node p = node.predecessor();                if (p == head && tryAcquire(arg)) {                    setHead(node);                    p.next = null; // help GC                    return interrupted;                }                if (shouldParkAfterFailedAcquire(p, node) &&                    parkAndCheckInterrupt())                    interrupted = true;            }        } catch (RuntimeException ex) {            cancelAcquire(node);            throw ex;        }    }
就是如果当前线程的前驱是头节点的话,就试着去再次获得锁,因为head节点是当前获得锁的线程。

若失败,则执行这个方法shouldParkAfterFailedAcquire,parkAndCheckInterrupt

意思就是如果获取失败,就挂起当前线程,进去这个方法里面,看一看

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {        int ws = pred.waitStatus;        if (ws == Node.SIGNAL)            /*             * This node has already set status asking a release             * to signal it, so it can safely park             */            return true;        if (ws > 0) {            /*             * Predecessor was cancelled. Skip over predecessors and             * indicate retry.             */    do {node.prev = pred = pred.prev;    } while (pred.waitStatus > 0);    pred.next = node;        } else {            /*             * waitStatus must be 0 or PROPAGATE. Indicate that we             * need a signal, but don't park yet. Caller will need to             * retry to make sure it cannot acquire before parking.              */            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);        }         return false;    }

    /**     * Convenience method to park and then check if interrupted     *     * @return {@code true} if interrupted     */    private final boolean parkAndCheckInterrupt() {        LockSupport.park(this);        return Thread.interrupted();    }
就是调用了LockSupport的park方法来挂起当前线程。interrupted的作用是干这个用的

  1. //清除中断标记,并返回上一次中断标记的值  
  2.     public static boolean interrupted() { ... }     

若当成的中断是true的话,下面就将执行这句话selfInterrupt方法

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

    /**     * Convenience method to interrupt current thread.     */    private static void selfInterrupt() {        Thread.currentThread().interrupt();    }

设置当前线程的中断标记,这里只是在线程上设置了一个中断标记,具体怎么处理这个中断标记,由应用程序来确定。


在看看unlock的时候,都做了一些什么

    public void unlock() {        sync.release(1);    }

    public final boolean release(int arg) {        if (tryRelease(arg)) {            Node h = head;            if (h != null && h.waitStatus != 0)                unparkSuccessor(h);            return true;        }        return false;    }

而这里面的unparkSuccessor就是unpark当前节点的下一个节点,使其运行。






0 0