Java多线程_生产者消费者模式1

生产者消费者模型
       具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。生产消费者模式如下图。(图片来自网络,侵删!)

 

 

生产者消费者模型的实现
  生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好。关键是如何处理多线程之间的协作。这其实也是多线程通信的一个范例。
  在这个模型中,最关键就是内存缓冲区为空的时候消费者必须等待,而内存缓冲区满的时候,生产者必须等待。其他时候可以是个动态平衡。值得注意的是多线程对临界区资源的操作时候必须保证在读写中只能存在一个线程,所以需要设计锁的策略。
       具体实现:

import java.util.LinkedList;

public class ProductorConsumerDemo {
    LinkedList<Integer> lists = new LinkedList<>(); // 定义存放物品的仓库
    int size = 10; // 定仓库的大小
    // 生产物品
    public synchronized void add(Integer i) { // 这里对临界资源的访问贯穿了整个方法,synchronized可以直接加到方法上
        if (lists.size() == size) { // 首先判断还能不能生产? 也就是容量到了size吗?
            try {
                this.wait(); // 不需要的生产 ,就等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            lists.add(i); // 把生产出来的物品放进仓库
            this.notifyAll(); // 唤醒消费者线程来消费
        }

    }

    // 消费
    public synchronized int remove() {
        if (lists.size() == 0) { // 判断有没有物品
            try {
                this.wait(); // 如果没有物品就等待, 释放锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            int i = lists.removeFirst(); // 有物品,就拿走一个
            if (lists.size() == 0) // 如果拿到了最后一个
            {
                this.notifyAll(); // 通知生产者生产物品
            }
            return i;
        }
        return -1;
    }

    public static void main(String[] args) {
        ProductorConsumerDemo pcd = new ProductorConsumerDemo();
        new Thread(new Runnable() {
            int count = 1;

            @Override
            public void run() {
                while (true) {
                    int i = count++;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    pcd.add(i);
                    System.out.println(Thread.currentThread().getName() + " 生产了第 " + i + " 个物品,还有" + pcd.lists);
                }
            }
        }, "生产者 ").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(110);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " 消费了第 " + pcd.remove() + "个物品");
                }
            }
        }, "消费者 ").start();
    }
}

结果:

 

这种方式很麻烦,在我的下一条博客中将介绍一种简单的实现方法。

posted @ 2019-01-17 17:51  橘子洲头。  阅读(270)  评论(0编辑  收藏  举报