欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java8 ReentrantLock Condition运用

程序员文章站 2022-03-19 15:31:20
Java8 ReentrantLock Condition在LinkedBlockingQueue中的使用场景1.持有的锁2.插入元素3.获取元素4.经验总结在LinkedBlockingQueue中的使用场景下面以LinkedBlockingQueue为例,分析ReentrantLock和Condition的作用。1.持有的锁/** Lock held by take, poll, etc */private final ReentrantLock takeLock = new Reentra...

在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>(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锁。

本文地址:https://blog.csdn.net/weixin_43858151/article/details/111886086

相关标签: # 多线程 Java