Java8 ReentrantLock Condition运用

Java8 ReentrantLock Condition运用

  • 在LinkedBlockingQueue中的使用场景
    • 1.持有的锁
    • 2.插入元素
    • 3.获取元素
    • 4.经验总结

在LinkedBlockingQueue中的使用场景

下面以LinkedBlockingQueue为例,分析ReentrantLock和Condition的使用。

1.持有的锁

/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock(); //获取元素锁

/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition(); //队列非空条件

/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock(); //插入元素锁

/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition(); //队列未满条件

2.插入元素

public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    if (e == null) throw new NullPointerException(); //若插入空元素,抛出空指针异常
    long nanos = unit.toNanos(timeout); //超时时间转换为时间戳
    final int c;
    final ReentrantLock putLock = this.putLock; //插入元素锁
    final AtomicInteger count = this.count; //队列长度
    putLock.lockInterruptibly(); //插入元素锁加锁
    try {
        while (count.get() == capacity) { //若队列已满,循环等待
            if (nanos <= 0L) //若方法执行超时
                return false; //返回false,插入元素失败
            nanos = notFull.awaitNanos(nanos); //释放锁和CPU资源,等待唤醒,若被唤醒,继续while循环
        }
        enqueue(new Node(e)); //若队列未满,且未超时,在队尾插入元素
        c = count.getAndIncrement(); //获取之前的队列长度,然后将队列长度+1
        if (c + 1 < capacity) //若队列未满
            notFull.signal();  //唤醒notFull
    } finally {
        putLock.unlock(); //释放插入元素锁
    }
    if (c == 0) //如果之前的队列长度为0
        signalNotEmpty(); //插入元素后,唤醒notEmpty
    return true; //返回true,插入元素成功
}

3.获取元素

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    final E x;
    final int c;
    long nanos = unit.toNanos(timeout); //超时时间转换为时间戳
    final AtomicInteger count = this.count; //队列长度
    final ReentrantLock takeLock = this.takeLock; //获取元素锁
    takeLock.lockInterruptibly(); //获取元素锁加锁
    try {
        while (count.get() == 0) { //若队列为空,循环等待
            if (nanos <= 0L) //若方法执行超时
                return null; //返回null,获取元素失败
            nanos = notEmpty.awaitNanos(nanos); //释放锁和CPU资源,等待唤醒,若被唤醒,继续while循环
        }
        x = dequeue(); //若队列非空,且未超时,获取队列首元素并从队列删除
        c = count.getAndDecrement(); //获取之前的队列长度,然后将队列长度-1
        if (c > 1) //若队列非空
            notEmpty.signal(); //唤醒notEmpty
    } finally {
        takeLock.unlock(); //释放获取元素锁
    }
    if (c == capacity) //如果之前的队列是满的
        signalNotFull(); //获取元素后,唤醒notFull
    return x; //返回获取的元素
}

4.经验总结

1. Condition:固定模式,配合while循环使用。1.等待资源满足条件退出循环;2.超时退出。
2. LinkedBlockingQueue的实现使用了takeLock、putLock,防止死循环,代码中避免同时获取两把锁,例如上面插入元素,释放putLock 锁之后再执行signalNotEmpty,获取takeLock锁。

你可能感兴趣的:(#,多线程,Java,java)