并发编程之condition的使用以及原理解析

Condition条件控制

作用:主要是通过ReentrantLock类里面的newCondition()方法获取lock上的一个条件,可以用于线程之间的通信

1)通过condition能够更加精细的控制多线程的休眠await与唤醒signal
2)在一个锁中,可以为多线程间建立不同的condition

Condition的使用阻塞队列

public class Consumer implements Runnable{
    private Queue<String> msg;
    private Lock lock ;
    private Condition condition ;
    private BlockingDeque blockingDeque;
    public Consumer(Queue<String> msg ,Lock lock ,Condition condition ) {
        this.msg = msg;
        this.lock = lock;
        this.condition = condition ;
    }
    @Override
    public void run() {
        while (true){
            lock.lock();
            while (msg.isEmpty()){
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("消费者消费:"+msg.remove());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            condition.signal();
            lock.unlock();
        }
    }
}
public class Producer implements Runnable{
    private Queue<String> msg;
    private Lock lock;
    private Condition condition ;
    private int maxSize;

    public Producer(Queue<String> msg ,Lock lock ,Condition condition ,int maxSize) {
        this.msg = msg;
        this.lock = lock;
        this.condition = condition ;
        this.maxSize = maxSize;
    }
    @Override
    public void run() {
        int i = 0;
        while (true){
            i++;
            lock.lock();
            while (msg.size()==maxSize){
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("生成者生成:"+msg.add("生成者生成:"+i));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            condition.signal();
            lock.unlock();
        }

    }
}

源码分析

调用await方法将线程放入到Condition队列中 -->释放锁–>判断当前节点是否在AQS同步队列中,如果在的话进行park阻塞通过node.waitStatus判断是否为condition node.pref前驱节点是否存在,最后一种为循环判断
		public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();//创建节点(单向),并把抢占到锁的节点移动到condition单向队列上
            Node node = addConditionWaiter();
             //完整释放锁(statu5->代表重入5次,完全释放相当于直接把5-》0)
             //并且唤醒等待队列的线程
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //判断这个节点是否在同步队列中,通过node.waitStatus判断是否为condition node.pref前驱节点是否存在,最后一种为循环判断
            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
            	//去除状态为cancled状态的节点
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }
        //完整释放锁(statu5->代表重入5次,完全释放相当于直接把5-》0)
        final int fullyRelease(Node node) {
	        boolean failed = true;
	        try {
	        	//获取锁的statu值
	            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) {
	    	//
	        if (tryRelease(arg)) {
	            Node h = head;
	            if (h != null && h.waitStatus != 0)
	            	//唤醒处于阻塞状态中的线程,相当于锁的释放
	                unparkSuccessor(h);
	            return true;
	        }
	        return false;
	    } 
	    //创建Condition单向队列
        private Node addConditionWaiter() {
            Node t = lastWaiter;//最后一个等待
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
            //去除状态为cancled状态的节点
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            //构建一个Node(CONDITION条件)队列,传递当前的线程
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }

signal唤醒

(有两种方式抢占:1、原Tail为CANCELLED状态会跳过unlock,是一个性能优化的体现,早一点唤醒(提前抢占锁)执行剩下的代码2、condition的节点transfer)
		public final void signal() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
        }
        private void doSignal(Node first) {
            do {
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }
        final boolean transferForSignal(Node node) {
        	//如果Node状态为CONDITION则修改为0 返回true,如果异常则返回false
	        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
	            return false;
	        //将Condition队列中的节点传输到AQS队列中,并且将执行AQS队列的逻辑
	        Node p = enq(node);
	        //p为AQS队列中的尾结点
	        int ws = p.waitStatus;
	        //当大于0时属于canceled状态(判断AQS队列中的尾结点tail是否为cancle(取消)状态)   判断ws 是否与 Node.SIGNAL状态相等
	        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
	            LockSupport.unpark(node.thread);
	        return true;
	    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值