Java 生产者-消费者模式

概念

生产者:生产数据的模块

消费者:消费数据的模块

缓冲区:生产者-消费者模式需要有一个缓冲区处于生产者和消费者之间,作为一个中介(一般都是用阻塞队列)。

队列(阻塞队列BlockingQueue)

优点

1.如果生产者直接调用消费者的某个方法,由于函数调用时同步的,那么在消费者处理完数据之前,生产者就一直在等待。如果消费者的处理速度很快可能还好,如果消费者处理数据很慢,那么生产者就要长时间等待,而不能进行下一步的操作。使用了生产者-消费者模式之后,生产者不用关心消费者的处理能力,直接将数据放入缓冲区就好

2.生产者把数据放入缓冲区,而消费者从缓冲区取出数据。这样可以降低生产者和消费者的耦合性,他们都依赖于某个缓冲区(队列)

缺点

在每次push时,可能涉及到堆内存的分配;在每次pop时,可能涉及堆内存的释放。假如生产者和消费者都很勤快,频繁地push、pop,那内存分配的开销就很大(可以用环形缓冲区解决)

实现类

1.在类库中包含了BlockingQueue的多种实现,其中,LinkedBlockingQueue 和ArrayBlockingQueue是FIFO队列,二者分别与LinkedList和ArrayList类似,但比同步List 拥有更好的并发性能。PriorityBlockingQueue 是一个按优先级排序的队列,当你希望按照某种顺序而不是FIFO来处理元素时,这个队列将非常有用。正如其他有序的容器一样,PriorityBlockingQueue 既可以根据元素的自然顺序来比较元素(如果它们实现了Comparable方法),也可以使用Comparator来比较。

2.SynchronousQueue,实际上它不是一个真正的队列,因为它不会为队列中元素维护存储空间。与其他队列不同的是,它维护一组线程,这些线程在等待着把元素加入(生产者)或移出(消费者)队列。

放入队列的数据注意事项

完整性

在传输过程中,要保证该数据单元的完整。要么整个数据单元被传递到消费者,要么完全没有传递到消费者。不允许出现部分传递的情形。

独立性

各个数据单元之间必须没有互相依赖,某个数据单元传输失败(队列满了时可能会丢弃后来的数据)不应该影响已经完成传输的单元;也不应该影响尚未传输的单元。如果不能保证独立性那么当数据丢失时会导致后续的逻辑非常复杂

颗粒度

有时出于性能等因素的考虑,可能会把N个业务对象打包成一个数据单元。那么,这个N该如何取值就是颗粒度的考虑了。太大的颗粒度可能会造成某种浪费;太小的颗粒度可能会造成性能问题。颗粒度的权衡要基于多方面的因素,以及一些经验值的考量。

代码

代码来源

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//使用阻塞队列BlockingQueue解决生产者消费者
public class BlockingQueueConsumerProducer {
    public static void main(String[] args) {
        Resource3 resource = new Resource3();
        //生产者线程
        ProducerThread3 p = new ProducerThread3(resource);
        //多个消费者
        ConsumerThread3 c1 = new ConsumerThread3(resource);
        ConsumerThread3 c2 = new ConsumerThread3(resource);
        ConsumerThread3 c3 = new ConsumerThread3(resource);
 
        p.start();
        c1.start();
        c2.start();
        c3.start();
    }
}
/**
 * 消费者线程
 * @author tangzhijing
 *
 */
class ConsumerThread3 extends Thread {
    private Resource3 resource3;
 
    public ConsumerThread3(Resource3 resource) {
        this.resource3 = resource;
        //setName("消费者");
    }
 
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (1000 * Math.random()));//模拟消费者处理数据时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource3.remove();//从队列中移除一个数据
        }
    }
}
/**
 * 生产者线程
 * @author tangzhijing
 *
 */
class ProducerThread3 extends Thread{
    private Resource3 resource3;
    public ProducerThread3(Resource3 resource) {
        this.resource3 = resource;
    }
 
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (1000 * Math.random()));//模拟生产数据
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource3.add();
        }
    }
}
class Resource3{
    private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);
    /**
     * 向资源池中添加资源
     */
    public void add(){
        try {
            resourceQueue.put(1);
            System.out.println("生产者" + Thread.currentThread().getName()
                    + "生产一件资源," + "当前资源池有" + resourceQueue.size() + 
                    "个资源");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 向资源池中移除资源
     */
    public void remove(){
        try {
            resourceQueue.take();
            System.out.println("消费者" + Thread.currentThread().getName() + 
                    "消耗一件资源," + "当前资源池有" + resourceQueue.size() 
                    + "个资源");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值