zoukankan      html  css  js  c++  java
  • 从使用角度看 ReentrantLock 和 Condition

    java 语言中谈到锁,少不了比较一番 synchronized 和 ReentrantLock 的原理,本文不作分析,只是简单介绍一下 ReentrantLock 的用法,从使用中推测其内部的一些原理。

    代码示例:

    public static void main(String[] args) throws InterruptedException {
            final ReentrantLock lock = new ReentrantLock();
            final Condition con1 = lock.newCondition();
            final Condition con2 = lock.newCondition();
            
    //        lock.lock();
            
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        con1.await();
                        System.out.println("wake from cond1");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            });
            t1.start();
            
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        con2.await();
                        System.out.println("wake from cond2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            });
            t2.start();
            
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        con2.await();
                        System.out.println("wake from cond2");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            });
            t3.start();
            
            Thread.sleep(100);
            try {
                lock.lock();
                System.out.println("lock.getQueueLength() = " + lock.getQueueLength());
                System.out.println("lock.getWaitQueueLength(con1) = " + lock.getWaitQueueLength(con1));
                System.out.println("lock.getWaitQueueLength(con2) = " + lock.getWaitQueueLength(con2));
                con1.signal();
                con2.signalAll();
                
                Thread.sleep(100);
                System.out.println("lock.getWaitQueueLength(con1) = " + lock.getWaitQueueLength(con1));
                System.out.println("lock.getWaitQueueLength(con2) = " + lock.getWaitQueueLength(con2));
            } finally {
                lock.unlock();
            }
    
        }

    lock 和 await 会改变 state 的值。

    以 ReentrantLock.getQueueLength 和 ReentrantLock.getWaitQueueLength 作为入口:前者作用是返回获取锁失败,处于等待状态的线程个数,后者是返回等待某一个 condition 的线程个数。

    // int java.util.concurrent.locks.ReentrantLock.getQueueLength()
    public final int getQueueLength() {
        return sync.getQueueLength();
    }
    
    // int java.util.concurrent.locks.AbstractQueuedSynchronizer.getQueueLength()
    public final int getQueueLength() {
        int n = 0;
        for (Node p = tail; p != null; p = p.prev) {
            if (p.thread != null)
                ++n;
        }
        return n;
    }

    很简单,就是遍历阻塞线程的链表。

    // int java.util.concurrent.locks.ReentrantLock.getWaitQueueLength(Condition condition)
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
    
    // int java.util.concurrent.locks.AbstractQueuedSynchronizer.getWaitQueueLength(ConditionObject condition)
    public final int getWaitQueueLength(ConditionObject condition) {
        if (!owns(condition))
            throw new IllegalArgumentException("Not owner");
        return condition.getWaitQueueLength();
    }
    
    // int java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.getWaitQueueLength()
    protected final int getWaitQueueLength() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        int n = 0;
        for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
            if (w.waitStatus == Node.CONDITION)
                ++n;
        }
        return n;
    }

    同样,也是遍历链表,不同的是,这是 Condition 的链表。

    现在,我们知道,ReentrantLock 中有 2 种不同的链表,其一是阻塞线程,其二是 Condition 等待链表,2 种链表都是使用 Node:

    // java.util.concurrent.locks.AbstractQueuedSynchronizer.Node 
    static final class Node {
        static final Node EXCLUSIVE = null;
        // 线程阻塞节点的状态
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        // condition 节点的状态
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
        volatile int waitStatus;
        volatile Node prev;
        volatile Node next;
        volatile Thread thread;
    }

    节点的类型表明链表的类型。

    看看 Condition 实现类的 api:

    public class ConditionObject implements Condition, java.io.Serializable {
        private static final long serialVersionUID = 1173984872572414699L;
        private transient Node firstWaiter;
        private transient Node lastWaiter;
    
        /**
         * Adds a new waiter to wait queue.
         * @return its new wait node
         */
        private Node addConditionWaiter() {
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
    
        public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }
    
        /**
         * Moves the longest-waiting thread, if one exists, from the
         * wait queue for this condition to the wait queue for the
         * owning lock.
         *
         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
         *         returns {@code false}
         */
        public final void signal() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }
    }

    在开头的示例中,创建了 2 个 Condition 对象,每个Condition 对象有一个自己的等待链表。

  • 相关阅读:
    git config (21)
    狗狗染头,一举天下成名
    K2使用总结K2简介
    K2使用总结流程设计
    如何组建开发团队谈面试
    如何组建开发团队谈谈团队组成
    如何组建开发团队谈招聘中的牛人
    作业题有感
    js对象学习笔记Function类型和对象
    非常认同的《SEO优化大全》
  • 原文地址:https://www.cnblogs.com/allenwas3/p/9130069.html
Copyright © 2011-2022 走看看