【Java多线程】生产者消费者模式

定义

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

图解:

这里写图片描述

实例

例1:wait、notify方法

public class ProductorAndConsumerTest {
    public static void main(String[] args) {
        Clerk2 clerk = new Clerk2();

        Productor2 pro = new Productor2(clerk);
        Consumer2 cus = new Consumer2(clerk);

        new Thread(pro, "2生产者 A").start();
        new Thread(cus, "2消费者 B").start();
        new Thread(pro, "2生产者 C").start();
        new Thread(cus, "2消费者 D").start();
    }
}

//店员
class Clerk2{
	private int product = 0;

	//进货
	public synchronized void get(){//循环次数:0
		while(product >= 1){//为了避免虚假唤醒问题,应该总是使用在循环中
			System.out.println("产品已满!");
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
		}

		System.out.println(Thread.currentThread().getName() + " : " + ++product);
		this.notifyAll();
	}

	//卖货
	public synchronized void sale(){//product = 0; 循环次数:0
		while(product <= 0){
			System.out.println("缺货!");

			try {
				this.wait();
			} catch (InterruptedException e) {
			}
		}

		System.out.println(Thread.currentThread().getName() + " : " + --product);
		this.notifyAll();
	}
}

//生产者
class Productor2 implements Runnable{
	private Clerk2 clerk;

	public Productor2(Clerk2 clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
			}

			clerk.get();
		}
	}
}

//消费者
class Consumer2 implements Runnable{
	private Clerk2 clerk;

	public Consumer2(Clerk2 clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			clerk.sale();
		}
	}
}

输出结果:

缺货!
缺货!
2生产者 A : 1
2消费者 D : 0
缺货!
缺货!
2生产者 C : 1
2消费者 B : 0
缺货!
缺货!
2生产者 A : 1
2消费者 D : 0
//中间省略很多行
缺货!
2生产者 C : 1
2消费者 D : 0
缺货!
2生产者 A : 1
2消费者 B : 0

分析:只有当生产者生产了数据,消费者才能消费,否则就缺货!

例2:await、signal方法

    public static void main(String[] args) {
        MyQueue queue = new MyQueue();
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
    }

    static class Producer implements Runnable {

        private MyQueue queue;

        Producer(MyQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.print("生产者");
                    queue.putEle(i + 1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    static class Consumer implements Runnable {

        private MyQueue queue;

        Consumer(MyQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.print("消费者");
                    queue.takeEle();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    static class MyQueue {
        Lock lock = new ReentrantLock();
        Condition prodCond  = lock.newCondition();
        Condition consCond = lock.newCondition();

        final int CAPACITY = 3;
        Object[] container = new Object[CAPACITY];
        int count = 0;
        int putIndex = 0;
        int takeIndex = 0;

        public void putEle(Object ele) throws InterruptedException {
            try {
                lock.lock();
                while (count == CAPACITY) {
                    System.out.println("队列已满:count=" + count + ",生产者休息。。。");
                    prodCond.await();
                }
                container[putIndex] = ele;
                System.out.print("生产元素:" + ele);
                putIndex++;
                if (putIndex >= CAPACITY) {
                    putIndex = 0;
                }
                count++;
                System.out.println(" 通知消费者去消费。。。");
                consCond.signalAll();
            } finally {
                lock.unlock();
            }
        }

        public Object takeEle() throws InterruptedException {
            try {
                lock.lock();
                while (count == 0) {
                    System.out.println("队列已空:count=0,消费者休息。。。");
                    consCond.await();
                }
                Object ele = container[takeIndex];
                System.out.print("消费元素:" + ele);
                takeIndex++;
                if (takeIndex >= CAPACITY) {
                    takeIndex = 0;
                }
                count--;
                System.out.println(" 通知生产者去生产。。。");
                prodCond.signalAll();
                return ele;
            } finally {
                lock.unlock();
            }
        }
    }


输出结果:

生产者生产元素:1 通知消费者去消费。。。
生产者生产元素:2 通知消费者去消费。。。
生产者生产元素:3 通知消费者去消费。。。
生产者队列已满:count=3,生产者休息。。。
消费者消费元素:1 通知生产者去生产。。。
消费者消费元素:2 通知生产者去生产。。。
消费者消费元素:3 通知生产者去生产。。。
消费者队列已空:count=0,消费者休息。。。
生产元素:4 通知消费者去消费。。。
生产者生产元素:5 通知消费者去消费。。。
消费元素:4 通知生产者去生产。。。
消费者消费元素:5 通知生产者去生产。。。



本人才疏学浅,若有错误,还请指出 谢谢!
发布了235 篇原创文章 · 获赞 292 · 访问量 40万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览