Condition

1、Condition介绍:

在Java程序中,任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object类上),主要包括wait()、wait(long)、notify()、notifyAll()方法,这些方法与synchronized关键字配合。实现等待/通知模式。

Condition接口也提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式。Condition可以替代synchronized的线程wait和notify通信方式。

一般都会将Condition对象作为成员变量。

当调用await()方法后,当前线程会 释放锁并在此等待,而其他线程调用Condition对象的signal()方法,通知当前线程后,当前线程 才从await()方法返回,并且在返回前已经获取了锁

public interface Condition {
    //当前线程进入等待状态直到被通知(signal)或中断。
    void await() throws InterruptedException;
    //当前线程进入等待状态直到被通知,该方法不响应中断。
    void awaitUninterruptibly();
    
    //当前线程进入等待状态直到被通知、中断或者超时,返回值表示剩余超时时间。
    long awaitNanos(long nanosTimeout) throws InterruptedException;
    
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    
    //当前线程进入等待状态直到被通知、中断或者到某个时间。如果没有到指定时间就被通知,方法返回true,否则,表示到了指定时间,返回false。
    boolean awaitUntil(Date deadline) throws InterruptedException;
    
    //	唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须获得与Condition相关联的锁。
    void signal();
    
    //唤醒所有等待在Condition上的线程,能够从等待方法返回的线程必须获得与Condition相关联的锁。
    void signalAll();
}

Condition的实现。创建一个condition对象是通过lock.newCondition(),会new出一个ConditionObject对象,ConditionObject是AQS的一个内部类。

public abstract class AbstractQueuedSynchronizer{
		
	static final class Node {

		//标记表示节点正在共享模式中等待
		static final Node SHARED = new Node();
			   
		//标记表示节点正在独占模式下等待
		static final Node EXCLUSIVE = null;

		//节点状态
		volatile int waitStatus 

		//当前节点/线程的前驱节点
		volatile Node prev 

		//当前节点/线程的后继节点
		volatile Node next; 

		//加入同步队列的线程引用
		volatile Thread thread;

		//等待队列中的下一个节点(和Condition配合使用)
		Node nextWaiter;
	}	
	
	
	//ConditionObject为AQS中的一个内部类
	public class ConditionObject implements Condition, java.io.Serializable {
		
            private transient Node firstWaiter;
        
            private transient Node lastWaiter;
	
	}
	
}

AQS内部维护了一个同步队列Node,如果是独占式锁的话,所有获取锁失败的线程的尾插入到同步队列(带头结点的双向队列),

同样的,condition内部也是使用同样的方式,内部维护了一个 等待队列(不带头结点的单向队列),如果一个线程调用了Condition.await()方法,那么该线程将会 释放锁、构造成节点加入等待队列并且线程状态转换为等待状态。

多次调用lock.newCondition()方法创建多个condition对象,也就是一个lock可以持有多个等待队列。

之前利用Object的wait和notify方式实际上是指在对象Object对象监视器上只能拥有一个同步队列和一个等待队列,

而并发包中的Lock拥有一个同步队列和多个等待队列。如图:

 

 

2、Condition.await实现原理

public final void await() throws InterruptedException {
	//await方法是响应中断的
    if (Thread.interrupted())
        throw new InterruptedException();
    // 1. 将当前线程加入到等待队列的队尾
    Node node = addConditionWaiter();
    //释放锁
    int savedState = fullyRelease(node);
    int interruptMode = 0;
	//是否在Condition等待队列中
    while (!isOnSyncQueue(node)) {
        // 当前线程进入到等待状态
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // 若不在 则自旋等待获取到同步状态(即获取到lock)
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
		//首先拿到Condition等待队列队尾,如果队尾已经失效了,那就清理掉
        unlinkCancelledWaiters();	
    // 被中断的情况
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

//将当前线程包装成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 node = new Node(Thread.currentThread(), Node.CONDITION);
	if (t == null)
		firstWaiter = node;
	else
		//尾插入到等待队列中
		t.nextWaiter = node;
	lastWaiter = node;
	return node;
}
//释放锁
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;
	}
}

//清理队尾失效的情况
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;
	}
}

3、Condition.signal/signalAll实现原理

public final void signal() {
    //判断当前线程是否获取到锁
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //获取等待队列中头节点
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);
}

private void 	(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        //1. 将头结点从等待队列中移除
        first.nextWaiter = null;
        //2. 在transferForSignal中对头结点做处理
    } while (!transferForSignal(first) && (first = firstWaiter) != null);
}

final boolean transferForSignal(Node node) {

    //更新状态为0
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;

    //调用AQS中的enq,将该节点加入到同步队列中自旋排队获取锁
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}
//将等待队列中所有节点都放入AQS同步队列中
private void doSignalAll(Node first) {
	lastWaiter = firstWaiter = null;
	do {
		Node next = first.nextWaiter;
		first.nextWaiter = null;
		transferForSignal(first);
		first = next;
	} while (first != null);
}

notify和signal都是按线程先进先出的顺序唤醒的 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值