生产者消费者模式需要满足:
1)生产者生产数据到缓冲区中,消费者从缓冲区中取数据;
2)缓冲区蛮,生产者线程阻塞;
3)缓冲区为空,消费者线程阻塞;
分析
1)定义缓存队列,选择一个集合当作缓存,给与缓存上线,缓存队列只有两种行为(生产数据和消费数据)。
2)定义生产者线程,调用缓存队列中的生产行为;
3)定义消费者线程,调用缓存队列中的消费者行为
第一种方式:
双向链表LinkedHashMap和Synchronized结合
定义缓存队列
- package pratice810;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.Map;
- public class QueueSX<T> {
- //公共缓存队列,1)生产,2)消费
- private int putIndex = 0;//数据插入的角标
- private int maxCount = 50;//缓存区最大长度
- private LinkedHashMap<Integer,T> lhm = new LinkedHashMap<Integer,T>();
- public synchronized void add(T msg){
- if(lhm.size() == maxCount){
- //如果缓存区达到最大数量,则阻塞生产者线程
- try {
- wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }else{
- notifyAll();//唤醒所有线程
- }
- lhm.put(putIndex, msg);
- putIndex = (putIndex+1 >= maxCount)?(putIndex+1) % maxCount:putIndex+1;
- }
- public synchronized T remove(){
- if(lhm.size() == 0){
- try {
- //如果没有数据,阻塞消费者线程
- wait();
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }else{
- notifyAll();
- }
- Iterator it = lhm.entrySet().iterator();
- T t = null;
- if(it.hasNext()){
- Map.Entry<Integer, T> entry = (Map.Entry<Integer, T>)it.next();
- t = entry.getValue();
- int index = entry.getKey();
- lhm.remove(index);
- }
- return t;
- }
- }
生产者
- package pratice810;
- //生产者线程
- public class productThread extends Thread {
- private QueueSX queuesx;
- public productThread(QueueSX queuesx){
- this.queuesx = queuesx;
- }
- @Override
- public void run(){
- for(int i=0;i<60;i++){
- QueueSX.add(String.valueOf(i));
- }
- }
- }
消费者
- package pratice810;
- //消费者线程
- public class ConsumerThread extends Thread{
- private QueueSX queuesx;
- public ConsumerThread(QueueSX queuesx){
- this.queuesx =queuesx;
- }
- public void run(){
- for(;;)
- queuesx.remove();
- }
- }
启动:
- package pratice810;
- public class productConsumerTest {
- //启动
- public static void main(String[] args) {
- QueueSX queuesx = new QueueSX();
- productThread pt = new productThread(queuesx);
- ConsumerThread ct = new ConsumerThread(queuesx);
- pt.start();//启动线程
- ct.start();
- }
- }
1)两个互斥线程,一个负责生产一个负责消费,线程不安全;
2)LinkedHashMap作为缓存队列,it.next()取出第一个数据,可以保证遍历的顺序;
3)为了保证互斥线程的安全性,需要做对应的处理,使用synchronized、wait()、notifyAll()来保证;
第二种方式
LinkedHashMap双向链表与lock结合。
private int putIndex = 0;//数据插入的角标
private int maxCount = 50;//缓存区最大长度
private Lock lock;
private Condition addCondition;
private Condition removeCondition;
public PublicQueue(){
lock = new ReentrantLock();
addCondition = lock.newCondition();
removeCondition =lock.newCondition();
}
第三种
直接使用阻塞队列BlockingQueue
private BlockingDeque<T> blockingDeque = new LinkedBlockingDeque<>(50);//缓冲区
转载:https://blog.csdn.net/Virgil_K2017/article/details/89283946