生产者消费者问题
(概念摘自:百度百科)
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
解决办法:
使用多线程阻塞实现消息队列
消息队列的应用场景
消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。
使用线程阻塞简单实现消息队列
需要用到的两个方法:
void wait() //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void notifyAll() //唤醒在此对象监视器上等待的所有线程。
创建消息队列Queue.java
package com.lingdu.thread;
import java.util.LinkedList;
/**
* 消息队列
* 生产者与消费者的关系
* @author LingDu
*/
public class Queue {
//创建一个链表
private LinkedList<String> queue = new LinkedList<String>();
//设置最大长度为10
private int maxSize = 10;
//创建一个对象锁
private static final Object lock = new Object();
public Queue(int maxSize) {
super();
this.maxSize = maxSize;
}
/**
* 用于存入消息
* @param msg
*/
public void pushMessage(String msg) {
synchronized (lock) {
// wait必须是在while循环里面
//大于最大值时则进入等待
while (queue.size() >= maxSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.push(msg);
// 唤醒所有
lock.notifyAll();
}
}
/**
* 用于取出消息
* @return
*/
public String getMessage() {
synchronized (lock) {
//链表大小小于1则进入等待
while (queue.size() < 1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//唤醒所有
lock.notifyAll();
//弹出消息
return queue.pop();
}
}
}
生产者ProducerTask
package com.lingdu.thread;
/**
* 生产者
* @author LingDu
*/
public class ProducerTask implements Runnable {
private Queue queue;
public ProducerTask(Queue queue) {
this.queue = queue;
}
@Override
public void run() {
/**
* 每次产生30个消息
*/
for (int i = 1; i <= 30; i++) {
queue.pushMessage("msg:" + i);
}
}
}
消费者ConsumerTask
package com.lingdu.thread;
/**
* 消费者
* @author LingDu
*/
public class ConsumerTask implements Runnable {
private Queue queue;
public ConsumerTask(Queue queue) {
this.queue = queue;
}
@Override
public void run() {
/**
* 每次处理10个消息
*/
for (int i = 0; i < 10; i++) {
String msg = this.queue.getMessage();
System.out.println(msg);
}
}
}
测试类Test.java
package com.lingdu.thread;
public class Test {
public static void main(String[] args) {
//创建链表对象并且初始化长度为10
Queue queue = new Queue(10);
//生产者对象
ProducerTask pro = new ProducerTask(queue);
//消费者对象
ConsumerTask con = new ConsumerTask(queue);
//产生消息
new Thread(pro).start();
//开启3个消费者同时取消息
new Thread(con).start();
new Thread(con).start();
new Thread(con).start();
}
}
使用消息队列的好处:
https://www.oschina.net/translate/top-10-uses-for-message-queue
最后这里介绍两个消息中间件Notify和MetaQ
- 消息系统的核心作用就是三点:解耦,异步和并行
有兴趣的小伙伴可以去看看