Condition,jdk源码阅读(四)

Condition是一个接口,AQS中的ConditionObject内部类实现了此接口。

使用方式:生产者,消费者模型

public class Producer implements Runnable{
    private Queue<String> msg;
    private int maxSize;
    private Lock lock;
    private Condition condition;

    public Producer(Queue<String> msg, int maxSize, Lock lock, Condition condition) {
        this.msg = msg;
        this.maxSize = maxSize;
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {
        int i = 0;
        while (true){
            i++;
            lock.lock();
            while (msg.size() == maxSize){
                System.out.println("生产者队列满了,先等待");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("生产者生产消息:" + i);
            msg.add("生产者的消息内容:" + i);
            condition.signal();
            lock.unlock();
        }
    }
}
public class Consumer implements Runnable {
    private Queue<String> msg;
    private int maxSize;
    private Lock lock;
    private Condition condition;

    public Consumer(Queue<String> msg, int maxSize, Lock lock, Condition condition) {
        this.msg = msg;
        this.maxSize = maxSize;
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {
        int i = 0;
        while (true){
            i++;
            lock.lock();
            while (msg.isEmpty()){
                System.out.println("消费者队列空了,先等待");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("消费者消费消息:"+ i + ","  + msg.remove());
            condition.signal();
            lock.unlock();
        }

    }
}
public class TestCondition {
    public static void main(String[] args) {
        Queue queue = new LinkedList();
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        int maxSize = 5;
        Producer producer = new Producer(queue,maxSize,lock,condition);
        Consumer consumer = new Consumer(queue,maxSize,lock,condition);

        Thread t1 = new Thread(producer);
        Thread t2 = new Thread(consumer);

        t1.start();
        t2.start();
    }
}

源码阅读

  • void await():方法
//        使获得锁的当前线程放弃资源,阻塞(直到被唤醒或interrupted)
        public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            //把当前获得锁的线程加入到Condition阻塞队列中(单线链表)
            Node node = addConditionWaiter();
//            释放锁,完整的释放,把重入的都释放掉。即state=0,并唤醒同步队列中阻塞的线程
            int savedState = fullyRelease(node);
            int interruptMode = 0;
//            判断当前节点是否在同步队列中(当前节点是在Condition队列中),不在的话就阻塞
            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);
        }
  1. 构造一个Condition阻塞队列,把当前线程加入其中,并返回当前线程节点
//        把当前获得锁的线程加入到Condition阻塞队列中(单线链表)
        private Node addConditionWaiter() {
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
//            构建一个Node,Node.CONDITION表示条件队列
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
  1. 如果t不为null且状态不为Node.CONDITION,说明此节点已经失效,需要清除
//        清除失效节点
        private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }
  1. 释放锁
//    释放锁,完整的释放,把重入的都释放掉。即state=0,并唤醒同步队列中阻塞的线程
    final int fullyRelease(Node node) {
        boolean failed = true;
        try {
            int savedState = getState();
//            释放锁
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }
//    释放锁
    public final boolean release(int arg) {
//      tryRelease(arg)重入状态的话state-1,减到0就变成无锁,无锁返回true
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
//                unpark唤醒
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
//        重入状态的话State-1,减到0就变成无锁
        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;
        }
  1. 判断当前节点是否在同步队列中(当前节点是在Condition队列中),不在的话就阻塞
//    判断当前节点是否在同步队列中
    final boolean isOnSyncQueue(Node node) {
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        if (node.next != null) // If has successor, it must be on queue
            return true;
        return findNodeFromTail(node);
    }
  1. todo…挂起之后,需要等待唤醒才能继续执行下面的代码。

  • void signal():方法
//        唤醒await阻塞的线程,就是唤醒Condition队列中的线程.
//        把Condition队列中的线程唤醒后,把它加入到同步队列中等待unlock
//        如果前一个节点已经失效,则直接唤醒
        public final void signal() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }
  1. 进入doSignal()方法,执行唤醒操作
        private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
//   检查node的状态是否被更改了,没被更改返回true,更改了就返回fasle,返回true结束循环
            } while (!transferForSignal(first) &&
//                   返回true则去除被更改的节点,重新循环直到找到正常的节点
                     (first = firstWaiter) != null);
        }
  1. 检查node的状态
//    检查node的状态是否被更改了,没被更改返回true,更改了就返回fasle
    final boolean transferForSignal(Node node) {
//        检测node的状态是否更改了,如果更改了就返回false
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

//        把node节点加入到同步队列中,并返回上一个节点,即tail
        Node p = enq(node);
        int ws = p.waitStatus;
//        提升性能的写法,如果p节点已经失效则直接唤醒node节点。
//        因为只有在unlock方法后才会唤醒同步阻塞队列中的线程,唤醒前需要把失效的节点移出去,
//        需要循环节点,p节点已经失效,就浪费了一次判断的过程,
//        这里直接唤醒还可以更快的把await后面没有执行完的代码执行完
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }
  1. 如果node状态正常没有失效,则把node加入到同步队列中
    private Node enq(final Node node) {
        //自旋
        for (;;) {
            Node t = tail;
//            尾节点=null
            if (t == null) { // Must initialize
//                初始化头部Node
                if (compareAndSetHead(new Node()))
//                    头节点,尾节点指向同一个节点Node
                    tail = head;
            } else {
//                当前节点的上一个节点指向尾节点
                node.prev = t;
//                更改尾部节点为当前节点
                if (compareAndSetTail(t, node)) {
//                    之前尾节点的下一个节点指向当前节点
                    t.next = node;
                    return t;
                }
            }
        }
    }
  1. 根据node的前一个节点tail的状态来决定是直接唤醒还是等unlock()方法后统一唤醒在进行抢占锁,如果提前唤醒,要回到之前await()方法挂起的地方,继续往下执行。
//            判断当前节点是否在同步队列中(当前节点是在Condition队列中),不在的话就阻塞
            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);
        }
  1. 唤醒后重新去抢占锁
//    去抢占锁或者阻塞,node为没有获取到锁的线程的node
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
//            自旋
            for (;;) {
//                p为当前node的上一个node
                final Node p = node.predecessor();
//                如果是head节点的话,会去抢占一次锁
                if (p == head && tryAcquire(arg)) {
//                    当前节点设置为头结点
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
//                shouldParkAfterFailedAcquire(Node pred, Node node)抢占锁失败后是否要挂起,true挂起,false不挂起
//                parkAndCheckInterrupt()用来挂起
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
//                    interrupted = true向上传递,让后续的代码知道线程中断过
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
  1. 抢占锁的过程就是ReentrantLock抢占锁的过程。

你可能感兴趣的:(jdk源码阅读)