Java构建生产者与消费者之间的生产关系模型,可以理解生产者生产message,存放缓存的容器,同时消费者进行消费需求的消耗,如果做一个合理的比喻的话:
生产者消费者问题是线程模型中的经典问题。解决生产者/消费者问题有两种方法:一是采用某种机制保护生产者和消费者之间的同步;二是在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,比较常用。生产者将消息提前生产好,存放在一个中间的区域(缓存),当消费者提出消费需求的时候进行,消息队列提供message及时提供与消费。
使用消息队列(缓存)的好处有以下几个:
1.解耦(去依赖),如果是消费者直接调用生产者,那如果生产者的代码变动了,消费者的代码也需要随之变动。
2.高效,如果消费者直接掉生产者,执行时间较长的话,会阻塞,影响其他业务的进行
3.负载均衡,如果消费者直接调生产者,那生产者和消费者就得在一起了,日后业务量非常大的话,要想减轻服务器的压力,想拆分生产和消费,就很困难。
简单来说:消息队列就是实现了生产者与消费者之间的一个“中介”,避免了生产者与消费者的直接接触造成的麻烦,提高了生产与消耗的运转效率。
说到效率就要提到多线程,为了提高效率,因此多线程的消息队列的构建会涉及到Java的并发编程以及容器的读写配置。
好的已经进入了考点范围,那我们废话不多说,直接进入正题。
JAVA语言的消费者与生产模型包括以下的两个方面:
(1)指定容器的数量以及属性参数:
//LinkedList容器的最大容量为2
public static final int MAX_SIZE = 2;
//选定存储容器为LinkedList
private static LinkedList<Integer> list = new LinkedList<>();
(2)指定生产者类对象(Producer)
static class Producer implements Runnable {
@Override
public void run() {
synchronized (list) {
//仓库容量已经达到最大值
while (list.size() == MAX_SIZE) {
System.out.println("仓库已满,生产者" + Thread.currentThread().getName() + "不可生产.");
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(1);
System.out.println("生产者" + Thread.currentThread().getName() + "生产, 仓库容量为" + list.size());
list.notify();
}
}
}
在整个的生产者所生产的message消息中,设计多线程的数据读写,因此采用sychronized保证读写的线程安全。
备注:当线程读写的时候,消息队列发生存储满的情况,则输出队列已满,否则则将元素写入队列中去。
(3)消费者对象类(Consumer):
static class Consumer implements Runnable {
@Override
public void run() {
synchronized (list) {
while (list.size() == 0) {
System.out.println("仓库为空,消费者" + Thread.currentThread().getName() + "不可消费.");
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.removeFirst();
System.out.println("消费者" + Thread.currentThread().getName() + "消费,仓库容量为" + list.size());
list.notify();
}
}
}
消费者的对象的实现原理与生产者的实现原理相同,保证线程安全的线程同步机制也均为sychronized与wait
整个的消息队列的实现流程为:
(1)生产者将生产的message存放进消息队列,
(2)如果消息队列中的元素已满则停止消息的生产。
(3)当消费者提出消费请求的时候,如果消息队列为空,将锁释放,调用线程的wait接口,等待生产者生产。
编写测试用例输出如下:
标签:Java,消费者,队列,list,生产者,源码,线程,消息 From: https://blog.51cto.com/u_13638291/6442031