1 生产者消费者问题
转载:Fighting2333
它描述是有一块缓冲区(队列实现)作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。在Java中这个数组线程阻塞的问题,多个用户同时发送多个请求,怎么保证不发生线程死锁,是我们要考虑的问题。
生产者消费者模式说明:
1.生产者只在仓库未满时进行生产,仓库满时生产者进程被阻塞;
2.消费者只在仓库非空时进行消费,仓库为空时消费者进程被阻塞;
3.当消费者发现仓库为空时会通知生产者生产;
3.当生产者发现仓库满时会通知消费者消费;
生产者消费者问题就是要保证不会出现没有商品但是消费者还是一直购买,商品满了但是生产者还是不断生产导致浪费的情况。
package com.zs.Mthread;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
/**
* 生产者消费者模式:使用Object.wait() / notify()方法实现
*/
public class ProducerConsumer {
private static final int CAPACITY = 5;
//申请一个容量最大的仓库
public static void main(String args[]){
Queue<Integer> queue = new LinkedList<Integer>();
Thread producer1 = new Producer("P1", queue, CAPACITY);
Thread producer2 = new Producer("P2", queue, CAPACITY);
Thread consumer1 = new Consumer("C1", queue, CAPACITY);
Thread consumer2 = new Consumer("C2", queue, CAPACITY);
Thread consumer3 = new Consumer("C3", queue, CAPACITY);
producer1.start();
producer2.start();
consumer1.start();
consumer2.start();
consumer3.start();
}
/**
* 生产者
*/
public static class Producer extends Thread{
private Queue<Integer> queue;
//队列作为仓库
String name;
int maxSize;
int i = 0;
public Producer(String name, Queue<Integer> queue, int maxSize){
super(name);
this.name = name;
this.queue = queue;
this.maxSize = maxSize;
}
@Override
public void run(){
while(true){
//while(condition)为自旋锁,为防止该线程没有收到notify()调用也从wait()中返回
//(也称作虚假唤醒),这个线程会重新去检查condition条件以决定当前是否可以安全
//地继续执行还是需要重新保持等待,而不是认为线程被唤醒了就可以安全地继续执行
//了,自旋锁当终止条件满足时,才会停止自旋,这里设置了一直执行,直到程序手动停
//止。
synchronized(queue){
//给队列加锁,保证线程安全
while(queue.size() == maxSize){
//当队列是满的时候,生产者线程等待,由消费者线程进行操作
try {
System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
//队列不为空的时候,生产者被唤醒进行操作
System.out.println("[" + name + "] Producing value : +" + i);
queue.offer(i++);
//因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一
//个 unchecked 异常,而调用 offer() 方法会返回 false
queue.notifyAll();
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 消费者
*/
public static class Consumer extends Thread{
private Queue<Integer> queue;
String name;
int maxSize;
public Consumer(String name, Queue<Integer> queue, int maxSize){
super(name);
this.name = name;
this.queue = queue;
this.maxSize = maxSize;
}
@Override
public void run(){
while(true){
synchronized(queue){
while(queue.isEmpty()){
try {
//队列为空,说明没有生产者生产的商品,消费者进行等待
System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
int x = queue.poll();
//如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,这里是模拟消费者取走商品的过程
// 但是新的 poll() 方法在用空集合调用时只是返回 null。因此新的方法更适合容易出现异常条件的情况。
System.out.println("[" + name + "] Consuming value : " + x);
queue.notifyAll();
//唤醒所有队列,消费者和生产者根据队列情况进行操作
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
[P1] Producing value : +0
[P1] Producing value : +1
[C3] Consuming value : 0
[C3] Consuming value : 1
Queue is empty, Consumer[C3] thread is waiting for Producer
Queue is empty, Consumer[C2] thread is waiting for Producer
Queue is empty, Consumer[C1] thread is waiting for Producer
[P2] Producing value : +0
[P2] Producing value : +1
[C1] Consuming value : 0
[C1] Consuming value : 1
Queue is empty, Consumer[C1] thread is waiting for Producer
Queue is empty, Consumer[C2] thread is waiting for Producer
Queue is empty, Consumer[C3] thread is waiting for Producer
[P1] Producing value : +2
[P1] Producing value : +3
[P1] Producing value : +4
[P1] Producing value : +5
[P1] Producing value : +6
Queue is full, Producer[P1] thread waiting for consumer to take something from queue.
[C3] Consuming value : 2
[C3] Consuming value : 3
[C2] Consuming value : 4
[C2] Consuming value : 5
[C2] Consuming value : 6
Queue is empty, Consumer[C1] thread is waiting for Producer
[P2] Producing value : +2