生产者消费者模型当中有三个实体,他们分别是:
生产者
消费者
缓冲队列
缓冲队列要求:
1.当缓冲队列为空时,不能往外取
2.当缓冲队列为满时,不能继续往里添加
对于缓冲队列的选择,可以选择线程安全的和线程非安全的.
线程安全的类 ,指的是类内共享的全局变量的访问必须保证是不受多线程形式影响的。如果由于多线程的访问(比如修改、遍历、查看)而使这些变量结构被破坏或者针对这些变量操作的原子性被破坏,则这个类就不是线程安全的。
线程不安全的包括:ArrayList.LinkedList等
线程安全的包括:LinkedBlockingQueue,ArrayBlockingQueue等
下面我们用线程不安全的LinkedList进行实验,看代码
缓冲队列内要加入的元素类
public class Task { }
生产者类
class Producer implements Runnable { private final Queue<Task> queue; private final static int MAX_SIZE = 2; Producer(Queue<Task> q) { queue = q; } public void run() { synchronized (queue) { //如果缓冲区满,该线程释放queue锁,等待 while (queue.size() >= MAX_SIZE) { try { queue.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果缓冲区不满,则继续添加任务 queue.add(new Task()); System.out.println("增加了一个任务,当前任务总数为" + queue.size()); //添加任务以后,通知所有处于等待状态的线程 queue.notifyAll(); } } }
消费者类
class Consumer implements Runnable { private final Queue<Task> queue; Consumer(Queue<Task> q) { queue = q; } public void run() { synchronized (queue) { //如果缓冲区内为空,消费者释放queue对象锁,处于等待状态 while (queue.size() <= 0) { try { queue.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如果缓冲区不为空,消费者将队首元素取走 queue.remove(); System.out.println("执行了一个任务,剩余任务总数为" + queue.size()); //取走后通知所有处于等待状态的线程 queue.notifyAll(); } } }
主函数类
class Setup { public static void main(String args[]) { Queue q = new LinkedList(); Producer p = new Producer(q); Producer p1 = new Producer(q); Producer p2 = new Producer(q); Producer p3 = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(p1).start(); new Thread(p2).start(); new Thread(c1).start(); new Thread(c2).start(); } }
执行结果:
增加了一个任务,当前任务总数为1
增加了一个任务,当前任务总数为2
执行了一个任务,剩余任务总数为1
增加了一个任务,当前任务总数为2
执行了一个任务,剩余任务总数为1