java 在同步代码中使用条件

设计了一个生产者消费者的例子,来研究这个问题。

 

一、实践

实现一个生产者消费者的例子。

1.实现思路

生产者生产一个事件,而消费者消费一个事件。所以有三个对象:生产者、消费者、事件。

事件应该是是事件类中的一个字段,参考消息队列,事件应该存放到一个链表中。

生产者生产一个事件,实际上是链表中增加了一个事件,所以事件类需要实现一个增加事件的方法。消费者消费一个事件,实际上是移除了链表中最前一个事件,所以实践类需要实现一个移除事件的方法。这两个方法都应该是同步的。

生产者类和消费者类都应该调用事件类中的生产和消费方法,同时这两个类都应该实现并发。

链表长度应该是有限的,应该有一个最大值,否则,如果生产速度大于消费速度,就会造成链表无限变大。所以,生产了一定数量事件后,如果达到了最大值,应该阻塞生产者类生产事件的线程。因为链表长度不可能小于0,所以当链表中没有事件时,消费者类也不可能继续消费事件。所以,如果当前事件数为0,应该阻塞消费者类消费事件的线程。

也就是说,以上两个方法应该能自己阻塞,并且相互唤醒。

在链表中事件到达最大值之前,生产者线程可以一直执行(生产事件),并且唤醒消费者线程(继续消费事件)。在链表中事件到达最大值的时候,生产者线程必须被阻塞(不能再生产事件了),等待消费者线程消费事件后将其唤醒(消费掉一些事件后,可以继续生产事件)。

同样的,在链表中还有事件时,消费者线程可以一直执行(消费事件),并且唤醒生产者线程(继续生产事件)。在链表中没有事件的时候,消费者线程必须被阻塞(没事件了怎么消费呢),等待生产者线程生产事件后将其唤醒(有事件之后就可以继续消费了)。

2.代码实现

代码应该还是比较好理解的。但是会出现一种奇怪的现象,那就是生产线程会一直执行,直到链表被事件充满,然后消费线程会一直执行,直到链表中的事件全部消费掉,如此反复。

3.一些问题

我本来的想实现的效果,是生产和消费交叉进行。在代码中,在生产事件之后,应该会立刻唤醒所有线程,进行消费:

但结果却是到了链表中事件到达最大值,生产线程被阻塞的时候,消费线程才开始消费。那么问题来了,为什么生产线程生产的时候,消费线程没有进行消费?为什么消费线程消费的时候,生产线程没有进行生产?

然后我看见有网友提问了,和我在想的问题一样:

为什么在生产者生产了一个产品后,notifyAll()方法没有唤醒消费者,去消费这个产品,而是在所有产品都生成后才去消费呢?还是唤醒了,必须执行完当前线程才会去执行呢?

然后也有相应的回答了:

这个东西跟concurrent的BlockingQueue是一样的东西。

这个使用场景不是像你说的:【生产了一个产品后,notifyAll()方法没有唤醒消费者,去消费这个产品,而是在所有产品都生成后才去消费】,而是因为:生产和消费速度是不一样的,可能因为IO或者业务链长度等等种种原因,致使生产消费速度有差异。所以需要一个临界区来缓存这些东西,而最易用且合理的容器就是list,FIFO嘛,通常道理上都是讲得过去的。

也就是说:produce > consume 时queue就会越来越大越来越大(搞笑了哈)最终OOM,所以这是要避免的;produce < consume 这是最理想的,也就是 queueSize = 0。

第二个问题,应该不用回答了。因为第一个问题和你想的不一样。

说实话,我看了之后还是没有弄懂…需要留到后面慢慢理解一下。

三、总结

本想着解决一下我的疑惑,结果又留下新的问题了…

发表评论

电子邮件地址不会被公开。 必填项已用*标注