ReentrantLock源码了解

    1)、ReentrantLock.tryLock
    //获取没有被其他线程持有的锁
    //1)、当没有被任何线程持有时,首先将计数器设置为1,并设置当前持有锁的线程为当前线程,最后返回true
    //2)、当被当前线程持有时,将计数器加1,最后返回true;
    //3)、否则返回false
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    //接着直接调用抽象类中的Sync.nonfairTryAcquire
    final boolean nonfairTryAcquire(int acquires) {
        //获取当前调用线程
        final Thread current = Thread.currentThread();
        //获取当前锁的状态,也就是当前锁的计数器的数值
        int c = getState();
        if (c == 0) {
            //此时说明,当前锁没有被任何线程持有
            if (compareAndSetState(0, acquires)) {
                //使用CAS操作,更新锁的状态,即锁的计数器的数值,若是成功,则将当前锁的线程持有者设置为当前线程
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            //根据JMM模型可知,同一个工作内存内是可见的,故同一个线程内是可见的,若相等,是同一个线程,且在同一个线程内不会发生setExclusiveOwnerThread时,在getExclusiveOwnerThread得到的不一样
            //此时说明,当前锁的线程持有者是当前线程
            //设置锁的计数器的值
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            //更新锁的状态,即锁的计数值的数值
            setState(nextc);
            return true;
        }
        return false;
    }

    2)、ReentrantLock.unlock
    //试图释放锁
    //1)、当前线程不是该锁的持有者时,抛出异常
    //2)、当前锁的计数器更改为0时,则设置当前锁的持有者为null
    //3)、否则,更新当前锁的状态,即锁的计数器的数值
    public void unlock() {
        sync.release(1);
    }

    //接着直接调用抽象类AbstractQueuedSynchronizer.release
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            //当锁的状态为0,或者说当前锁没有持有者时,需要唤醒当前锁上挂起的线程
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

    //再接着直接调用抽象类Sync.tryRelease
    protected final boolean tryRelease(int releases) {
        //计算当前锁的计数器的数值
        int c = getState() - releases;
        //判断当前线程是否是锁的持有者,若不是,则抛出异常
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            //当计数器的数值为0,说明此时锁没有持有者了,故先更新线程持有者,之后再去更新锁的状态,这样当去获取锁的状态时,此时的锁的持有者必然是更新后的,这样锁的释放和锁的获取就能保证一致的可见性了。
            free = true;
            setExclusiveOwnerThread(null);
        }
        //更新锁的状态,即锁的计数器的数值
        setState(c);
        return free;
    }

    //直接调用AbstractQueuedSynchronizer.unparkSuccessor
    //唤醒当前节点后的第一个非取消节点中的线程
    private void unparkSuccessor(Node node) {
        
        //尝试更新当前节点的状态
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        //获取当前节点后的第一个非取消节点,并唤醒该节点中挂起的线程
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            //从尾节点开始查找,直到当前节点,即可得到一个当前节点后的第一个非取消节点
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }

        //唤醒线程
        if (s != null)
            LockSupport.unpark(s.thread);
    }

    3)、ReentrantLock.lock
    //申请锁
    public void lock() {
       sync.lock();
    }

    31)、非公平锁
    //直接调用NonfairSync.lock
    final void lock() {
        //当通过CAS判断当前锁是否没有持有者,若是,则直接设置当前锁的持有者为当前线程;
        //否则,再次尝试加锁,最后还不成功,就如等待队列,线程挂起,直到被唤醒为止
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    //直接调用AbstractQueuedSynchronizer.acquire
    public final void acquire(int arg) {
        //尝试获取非公平锁,当失败时,就将当前线程入等待队列,线程挂起,直到被挂起
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

    //直接调用NonfairSync.tryAcquire
       protected final boolean tryAcquire(int acquires) {
           //尝试获取非公平锁
        return nonfairTryAcquire(acquires);
    }

    //直接调用AbstractQueuedSynchronizer.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) {
            //当前链表已经初始化,则CAS尝试将排他锁节点更改为链表的尾节点

            //设置当前节点的前一个节点为当前链表的尾节点
            node.prev = pred;
            //当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

    //直接调用AbstractQueuedSynchronizer.compareAndSetTail
    //原子更新链表的尾节点
    private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }

    //直接调用AbstractQueuedSynchronizer.enq
    //使用CAS原子性将节点插入到链表尾部
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                //当没有初始化时,进行头结点与尾节点初始化,成功后,将头结点与尾节点指向同一个处对象
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //将节点插入到链表尾部

                //设置当前节点的前一个节点为当前链表的尾节点
                node.prev = t;
                //当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

    //直接调用AbstractQueuedSynchronizer.acquireQueued
    //当当前节点为等待队列中的第一个节点时,获取到锁
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                //当当前节点的前节点为头结点,并为当前线程尝试获取锁,成功时,设置当前节点为头结点,并将当前节点的前节点的下一个节点取消,使之没有被引用,这样可以被GC回收
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }    
                //设置当前节点的前节点状态为唤醒状态,且将当前节点挂起
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    //直接调用AbstractQueuedSynchronizer.setHead
    //设置当前节点为头结点,并将当前节点的前节点置为空,以及将当前节点持有的线程设置为空
    private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.prev = null;
    }

    //直接调用AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            //当当前节点的前节点状态为唤醒时,则表明下一个被执行的节点是当前节点,即线程会被唤醒
            return true;
        if (ws > 0) {
               //当当前节点的前节点为取消的节点,则往前查找一个非取消的节点
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            //将查找的非取消节点的下一个节点更新为当前节点
            pred.next = node;
        } else {
            //尝试将当前节点的前节点的状态设置为唤醒状态
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

    //直接调用AbstractQueuedSynchronizer.compareAndSetWaitStatus
       //尝试更新节点的状态
    private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) {
        return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update);
    }

    //直接调用AbstractQueuedSynchronizer.parkAndCheckInterrupt
    //将当前线程挂起
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

    

 

 

Semaphore:资源控制,是线程同步的工具类,默认是公平策略;如停车场,最多只有100个车位,故当满时,只能出一个之后,才能进一个;
当新建时,需指定控制的资源的个数,即同时进行的线程数,还有就是使用的是公平还是非公平的策略,默认是非公平;
acquire获取资源;
release释放资源;

CountDownLatch:满足条件时触发;如赛跑,在开始前,所有运动员准备好之后,才能开始;当所有运动员到达终点时,才能结束;还如,当获取专辑的所有视频资源信息时,只有所有的视频信息获取到之后,才能进行之后的操作;当新建时,需要指定锁计数的个数;

await:等待锁计数为0,之前一直阻塞
countDown:递减计数器的计数,如果计数达到0,则释放所有等待的线程;

实际操作都是由其属性Sync来进行,且该属性对象继承了AbstractQueuedSynchronizer类;

参考资料:
http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html
http://mouselearnjava.iteye.com/blog/1921468

 

posted @ 2016-09-23 10:45  qingyezhu  阅读(239)  评论(0编辑  收藏  举报