Java 多线程设计模式之Producer-Consumer

来源:互联网 发布:float定义数组 编辑:程序博客网 时间:2024/06/06 03:33

Producer-Consumer 模式通过在数据的生产者和消费者之间引入一个通道(Channel, 暂时可以将其简单地理解为一个队列)对二者进行解耦(Decouping):生产者将其生产的数据放入通道,消费者从相应通道中取出数据进行消费,生产者和消费者各自运行在各自的线程中,从而使双方处理速率互补影响。

7.4.1 通道积压

当消费者的处理能力低于生产者的处理能力时,随着时间的推移,通道中存储的“产品”会越来越多而出现挤压现象。常见的处理方法有两种:
1. 使用有界阻塞队列,使用有界阻塞队列(如ArrayBlokingQueue 和带容量限制的LinkedBlockingQueue)作为Channel 参与者的实现可以实现将消费者的处理压力“反弹”给生产者。具体莱索,当通道的有界阻塞队列逐渐积压到队列满,此时生产者线程会被阻塞直到相应的消费者“消费”了队列的一些”产品“,使得队列非满。
2. 使用带流量控制的无界阻塞队列。使用无界阻塞队列(如不带容量限制的LinkBlockingQueue),借助控制流量实现,即对同一时间内可以有多少个生产者线程往通道中存储”产品“进行限制。

7.4.2 工作窃取方法

如果一个通道实例对应于多个队列实例,那么就可以实现多个消费者线程从通道中取“产品”的时候访问的是各自的队列实例,此时,各个消费者线程修改队列的头指针并不会导致锁竞争。
工作窃取(Work Stealing) 算思想,当一个消费者线程处理完该线程对应的队列中的“产品”时,它可以继续从其他消费者线程对应的队列中取出“产品”进行处理。

JDK 1.5 引入的标准库类 java.util.concurrent.ThreadPoolExecutor 可以看成是Producer-Consummer模式的可服用实现。 ThreadPoolExecutor 内部维护的工作队列和工作者线程相当于Producer-Consumer 模式的Channel 参与者和Consumer 参与者。而ThreadPoolExecutor 的客户端代码则相当于Producer 参与者。

阅读全文
0 0