JUC学习之生产者和消费者
1.生产者和消费者的定义
生产者和消费者即线程间的通信的问题的两种角色,生产者生产消费者需要的资源,消费者把资源做成产品(消耗掉)。
只要是并发编程就必须加锁,因为多线程的情况下不加锁是不安全的,会导致数据错乱。
2.生产者和消费者的实现
等待(逻辑判断是否等待)==》业务(具体生产加减业务实现)==》通知(完成业务后等待,并且通知唤醒其他线程工作)
3.虚假唤醒
3.1 虚假唤醒的产生
虚假唤醒是当一个条件满足时,很多的线程被唤醒了,但是只有一部分是有用的唤醒,其他都是无用的唤醒。
如果是两个线程,用if进行等待的逻辑判断一般不会出现问题,但是两个以上线程的时候用if进行等待的逻辑判断时,会出现虚假唤醒的情况。
比如执行生产者线程A的等待逻辑if判断一次后,生效进入wait等待的阶段,这个生产者线程线程A,只是阻塞了并没有结束,wait后会释放锁,唤醒其他线程,其中可能包括另外一个的生产者线程B,线程B也要进行逻辑判断和A一样会进入wait状态,当消费者线程C唤醒时,会将线程A和线程B同时唤醒,而此时线程A和线程B已经在if判断中,所以等于跳过了逻辑判断,直接进行后面的业务操作,就会出现数据异常状态。
3.2 如何解决虚假唤醒
使用while进行生产者和消费者的等待逻辑判断(尤其是两个以上线程),在一个线程判定为等待的时候,去唤醒其他线程,在这个唤醒的线程拿到锁后,会先进行判断,符合后才会进行业务代码。
解决线程中的虚假唤醒问题,主要在于阻塞到就绪的状态切换间加上判断,但是每次进行判断(while循环),会很浪费资源,cpu会一直占用着资源。
4.synchronized和lock实现生产者和消费者问题的区别
synchronized版是使用wait()方法进行阻塞线程(等待),notify()或者notifyAll()方法进行唤醒线程;
Lock锁版是使用Condition接口下的await()方法进行阻塞线程(等待),signal()或signalAll()方法进行唤醒线程,并且可以精准的唤醒线程(可以通过设置标记,来指定不同的监视器lock.newCondition())。
- 点赞
- 收藏
- 关注作者
评论(0)