admin管理员组

文章数量:1599532

Condition与Lock的方法



  Condition与Lock是两个接口,以上是它们内部定义的方法。Lock中有一个newCondition方法,所以Condition都是从Lock中创建出来的。

Condition实现原理

  以读写锁为例来看原理:

public class ReentrantLock implements Lock, java.io.Serializable {
	...
	public Condition newCondition() {
        return sync.newCondition();
    }
}

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
	...
	public static class ReadLock implements Lock, java.io.Serializable {
		...
		public Condition newCondition() {
            throw new UnsupportedOperationException(); //读锁不支持Condition
        }
	}
	...
	public static class WriteLock implements Lock, java.io.Serializable {
		...
		public Condition newCondition() {
            return sync.newCondition();
        }
	}
}

  读写锁中的读锁不支持Condition,而写锁和互斥锁支持Condition。

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer implements java.io.Serializable {
    public class ConditionObject implements Condition, java.io.Serializable {
    	...
    	private transient Node firstWaiter;// 阻塞队列队头
        private transient Node lastWaiter; // 阻塞队列队尾
        ...
    }
}

  Sync继承自AQS,AQS有ConditionObject类,ConditionObject内定义了阻塞队列。
Sync类内定义了newCondition()方法得到ConditionObject,而写锁和互斥锁都调用了sync的newCondition()。

final ConditionObject newCondition() {
    return new ConditionObject();
}

await()实现

  

public final void await() throws InterruptedException {
    if (Thread.interrupted())           //在执行await()时,收到中断信号,抛出异常
        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);   // 被中断唤醒时,向外抛出异常 
}

//addConditionWaiter()的具体实现,线程在调用await()时,已经先拿到锁了,
//所以,在往队列添加线程时,不用CAS操作
private Node addConditionWaiter() {
    Node t = lastWaiter;
    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;
}
//checkInterruptWhileWaiting(Node node)的实现
private int checkInterruptWhileWaiting(Node node) {
    return Thread.interrupted() ?
           (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0;
}
final boolean transferAfterCancelledWait(Node node) {
    if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { //尝试将线程状态从条件状态设置为同步状态0,成功后将节点加入AQS同步队列尾部
        enq(node);
        return true;
    }
    while (!isOnSyncQueue(node)) // 设置失败后,自旋尝试让当前线程的CPU执行时间让出,直到唤醒的节点在AQS同步队列为止
        Thread.yield();
    return false;
}

  线程被唤醒有两种可能,别的线程调用unpark()或者中断唤醒。所以在被重新唤醒后要判断是否是中断唤醒,如果是,则跳出循环,然后抛出异常。而如果是被signal()唤醒的话,线程会被放到同步队列中,同样会跳出循环。

awaitUninterruptibly()的实现

public final void awaitUninterruptibly() {
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    boolean interrupted = false;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if (Thread.interrupted())
            interrupted = true;
    }
    if (acquireQueued(node, savedState) || interrupted)
        selfInterrupt();
}

  与await()的区别在于,收到中断后不会抛出异常,也就是不响应异常。

signal()的实现

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) {
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) //修改线程状态,从条件等待修改为运行状态0
        return false;
    Node p = enq(node); //将节点放进同步队列里
    int ws = p.waitStatus;
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread); //唤醒线程
    return true;
}

  signalAll()的原理与signal()类似,不再分享。

总结:Condition与Lock的关系是Condition是Lock的一部分,可以理解为一个锁Lock对应若干个条件Condition,调用await()时会将当前的线程加入到条件队列中,signal()则是将条件队列中的线程加入到同步队列中。
  调用await()的作用相当于sychronized里调用wait(),signal()则相当于notify()。

  Lock和synchronized对比:1、synchronized是非公平锁,而ReentrantLock可以指定其公平性。2、Synchronized不能响应中断,而ReentrantLock可以。3、synchronized靠执行嵌套的代码块获取锁和释放锁,ReentrantLock通过调用方法来控制,更加灵活。4、synchronized是JVM实现的,而ReentrantLock是JDK实现的。5、一个ReentrantLock可以绑定多个Condition对象,而synchronized是绑定一个对象。6、新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同。


参考资料:《Java并发实现原理:JDK源码剖析》

本文标签: conditionLock