1、简介:
生产者-消费者(producer-consumer)问题是一个著名的线程同步问题。它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去消费。为使生产者与消费者之间能够并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者将它所生产的产品放入一个缓冲区中;消费者可以从一个缓冲区中取走产品产生消费。尽管所有的生产者线程和消费者线程都是以异步方式运行的,但他们之间必须保持同步,即不允许消费者到一个空缓冲区去消费,也不允许生产者向一个已经被占用的缓冲区投放产品。【转】
2、 wait()、notify(),notifyAll()的使用
obj.wait()方法将使本线程挂起,并释放obj对象的monitor。只有其他线程调用obj对象的notify()或notifyAll()时,才可以被唤醒。
obj.notifyAll()方法唤醒所有该obj对象相关的沉睡线程,然后被唤醒的众多线程开始竞争obj对象的monitor占有权,最终得到的那个线程会继续执行下去,但其他线程还将继续等待。
obj.notify()方法是随机唤醒一个沉睡线程。
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,
如:
synchronized(x){
x.notify()
//或者wait()
}
以上内容说明了为什么调用wait(),notify(),notifyAll()的线程必须要拥有obj实例对象的monitor占有权。
wait(),notify(),notifyAll() 方法必须在synchronized 方法内调用
每个对象实例都有一个等待线程队列。这些线程都是等待对该对象的同步方法的调用许可。对一个线程来说,有两种方法可以进入这个等待线程队列。一个是当其他线程执行同步方法时,自身同时也要执行该同步方法;另一个是调用obj.wait()方法。
当同步方法执行完毕或者执行wait()时,其他某个线程将获得对象的访问权。当一个线程被放入等待队列时,必须要确保可以通过notify()的调用来解冻该线程,以使其能够继续执行下去。
3 例子:
public class Queue {
List<String> list=new LinkedList<String>();
public synchronized String getRequest(){
if (list.size()==0) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return list.remove(0);
}
public synchronized void putRequest(String msg){
list.add(msg);
this.notifyAll();
}
}
生产者:
import java.util.Random;
public class Producer extends Thread {
private Queue queue;
private String clientName;
public Producer(Queue queue, String clientName) {
super(clientName);
this.queue = queue;
this.clientName = clientName;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
System.out.println("开始生产");
for (int i = 0; i < 10; i++) {
queue.putRequest(new Random().nextInt(1000)+" ");
}
System.out.println("生产结束");
}
}
消费者:
public class Consumer extends Thread {
private boolean stop = false;
private Queue queue;
public Consumer(boolean stop, Queue queue) {
super();
this.stop = stop;
this.queue = queue;
}
public void shutdown() {
stop = true;
this.interrupt();
try {
this.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
System.out.println("开始消费");
while (!stop) {
System.out.println("..");
System.out.println("Consumer"+queue.getRequest());
}
System.out.println("[消费结束] shutdown.");
}
}
Mian:
public static void main(String[] args) {
// TODO Auto-generated method stub
Queue queue=new Queue();
Consumer consumer=new Consumer(false, queue);
consumer.start();
for (int i = 0; i < 1; i++) {
Producer rroducer=new Producer(queue, " >>"+i);
rroducer.start();
}
}
参考: