并发(四):ReentrantLock之条件等待队列

大纲内容

条件等待队列

生产者-消费者Demo

在这里插入图片描述
详细文案可以看下链接, 关注一波, 后期分享经典面试题

并发(四):ReentrantLock之条件等待队列

并发(四):ReentrantLock之条件等待队列

并发(四):ReentrantLock之条件等待队列

并发(四):ReentrantLock之条件等待队列

并发(四):ReentrantLock之条件等待队列

条件等待队列
在并发(三):ReentrantLock类中,谈到了锁,每个ReentrantLock锁对应很多个条件等待队列,而synchronized锁只存在一个条件等待队列。
//图中的ReentrantLock定义了两个条件等待队列。
public class Bamboo {
private int bambooCount = 0;
private boolean flag = false;

Lock lock = new ReentrantLock();
Condition producerCondition = lock.newCondition();
Condition consumerCondition = lock.newCondition();


public void producerBamboo() {
    lock.lock(); // 获取锁资源
    try {
        while (flag) { // 如果有竹子
            try {
                producerCondition.await(); // 挂起生产竹子的线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bambooCount++; // 竹子数量+1
        System.out.println(Thread.currentThread().getName() + "....生产竹子,目前竹子数量:" + bambooCount);
        flag = true; // 竹子余量状态改为true
        consumerCondition.signal(); // 生产好竹子之后,唤醒消费竹子的线程
    } finally {
        lock.unlock(); // 释放锁资源
    }
}

public void consumerBamboo() {
    lock.lock(); // 获取锁资源
    try {
        while (!flag) { // 如果没有竹子
            try {
                consumerCondition.await(); // 挂起消费竹子的线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bambooCount--; // 竹子数量-1
        System.out.println(Thread.currentThread().getName() + "....消费竹子,目前竹子数量:" + bambooCount);
        flag = false; // 竹子余量状态改为false
        producerCondition.signal(); // 消费完成竹子之后,唤醒生产竹子的线程
    } finally {
        lock.unlock(); // 释放锁资源
    }
}

}

/**

  • ------------------分割线--------------------
    **/
    // 测试类
    class ConditionDemo {
    public static void main(String[] args) {
    Bamboo bamboo=new Bamboo();
    // 生产者线程组
    Thread t1 = new Thread(()->{
    bamboo.producerBamboo();
    }, “生产者-A”);
    Thread t2 = new Thread(()->{
    bamboo.producerBamboo();
    }, “生产者-B”);
    Thread t3 = new Thread(()->{
    bamboo.producerBamboo();
    }, “生产者-C”);

     // 消费者线程组
     Thread t4 = new Thread(()->{
         bamboo.consumerBamboo();
     }, "消费者-D");
     Thread t5 = new Thread(()->{
         bamboo.consumerBamboo();
     }, "消费者-E");
     Thread t6 = new Thread(()->{
         bamboo.consumerBamboo();
     }, "消费者-F");
    
     t1.start();
     t2.start();
     t3.start();
     t4.start();
     t5.start();
     t6.start();
    

    }
    }
    输出:
    生产者-B…生产竹子,目前竹子数量:1
    消费者-D…消费竹子,目前竹子数量:0
    生产者-A…生产竹子,目前竹子数量:1
    消费者-E…消费竹子,目前竹子数量:0
    生产者-C…生产竹子,目前竹子数量:1
    消费者-F…消费竹子,目前竹子数量:0

本文定义了六个线程,生产线程A,B,C,消费线程D,E,F,六个线程都尝试去获取锁,当线程A成功获取锁时,其他线程都会阻塞在同步阻塞队列中,修改waitStatus状态为-1,同时park住线程。
假设线程A先执行producerBamboo()方法,由于flag被volatile关键字锁修饰,固线程之间可见,由于flag是false,固不会将自己放入条件等待队列中,

竹子数量自增+1,设置volatile flag=true,则说明有竹子,尝试去唤醒条件等待队列(消费)中唤醒消费线程。

public void producerBamboo() {
lock.lock(); // 获取锁资源
try {
while (flag) { // 如果有竹子
try {
producerCondition.await(); // 挂起生产竹子的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bambooCount++; // 竹子数量+1
System.out.println(Thread.currentThread().getName() + “…生产竹子,目前竹子数量:” + bambooCount);
flag = true; // 竹子余量状态改为true
consumerCondition.signal(); // 生产好竹子之后,唤醒消费竹子的线程
} finally {
lock.unlock(); // 释放锁资源
}
}
当条件等待队列(消费)中有线程时,是因为消费者先获取了锁,然后根据flag=flase,进入了while判断中,获取锁的消费线程调用了 consumerCondition.await()。把当前线程放入到条件等待队列中addConditionWaiter(),然后消费线程尝试释放锁,同时判断当前消费线程是否在同步阻塞队列中,如果不在,则说明可以阻塞。

public final void await() throws InterruptedException {
if (Thread.interrupted())
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);
}

private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
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;
}
当条件等待线程(消费)中没有线程时,生产者尝试去调用doSignal(),如果为null,则什么都不会执行。
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}

如果线程B获取到锁时,发现flag为true,则把自己构造成Node节点,放入条件等待队列中,同时释放锁,然后唤醒消费同步等待队列中的线程尝试去消费锁。这样就实现了生产者-消费者的demo了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值