浅谈java线程中生产者与消费者的问题
一、概念
生产者与消费者问题是一个金典的多线程协作的问题.生产者负责生产产品,并将产品存放到仓库;消费者从仓库中获取产品并消费。当仓库满时,生产者必须停止生产,直到仓库有位置存放产品;当仓库空时,消费者必须停止消费,直到仓库中有产品。
解决生产者/消费者问题主要用到如下几个技术:1.用线程模拟生产者,在run方法中不断地往仓库中存放产品。2.用线程模拟消费者,在run方法中不断地从仓库中获取产品。3
.仓库类保存产品,当产品数量为0时,调用wait方法,使得当前消费者线程进入等待状态,当有新产品存入时,调用notify方法,唤醒等待的消费者线程。当仓库满时,调用wait方法,使得当前生产者线程进入等待状态,当有消费者获取产品时,调用notify方法,唤醒等待的生产者线程。
二、实例
packagebook.thread.product;
publicclassConsumerextendsThread{
privateWarehousewarehouse;//消费者获取产品的仓库
privatebooleanrunning=false;//是否需要结束线程的标志位
publicConsumer(Warehousewarehouse,Stringname){
super(name);
this.warehouse=warehouse;
}
publicvoidstart(){
this.running=true;
super.start();
}
publicvoidrun(){
Productproduct;
try{
while(running){
//从仓库中获取产品
product=warehouse.getProduct();
sleep(500);
}
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//停止消费者线程
publicvoidstopConsumer(){
synchronized(warehouse){
this.running=false;
warehouse.notifyAll();//通知等待仓库的线程
}
}
//消费者线程是否在运行
publicbooleanisRunning(){
returnrunning;
}
}
packagebook.thread.product;
publicclassProducerextendsThread{
privateWarehousewarehouse;//生产者存储产品的仓库
privatestaticintproduceName=0;//产品的名字
privatebooleanrunning=false;//是否需要结束线程的标志位
publicProducer(Warehousewarehouse,Stringname){
super(name);
this.warehouse=warehouse;
}
publicvoidstart(){
this.running=true;
super.start();
}
publicvoidrun(){
Productproduct;
//生产并存储产品
try{
while(running){
product=newProduct((++produceName)+"");
this.warehouse.storageProduct(product);
sleep(300);
}
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//停止生产者线程
publicvoidstopProducer(){
synchronized(warehouse){
this.running=false;
//通知等待仓库的线程
warehouse.notifyAll();
}
}
//生产者线程是否在运行
publicbooleanisRunning(){
returnrunning;
}
}
packagebook.thread.product;
publicclassProduct{
privateStringname;//产品名
publicProduct(Stringname){
this.name=name;
}
publicStringtoString(){
return"Product-"+name;
}
}
packagebook.thread.product;
//产品的仓库类,内部采用数组来表示循环队列,以存放产品
publicclassWarehouse{
privatestaticintCAPACITY=11;//仓库的容量
privateProduct[]products;//仓库里的产品
//[front,rear]区间的产品未被消费
privateintfront=0;//当前仓库中第一个未被消费的产品的下标
privateintrear=0;//仓库中最后一个未被消费的产品下标加1
publicWarehouse(){
this.products=newProduct[CAPACITY];
}
publicWarehouse(intcapacity){
this();
if(capacity>0){
CAPACITY=capacity+1;
this.products=newProduct[CAPACITY];
}
}
//从仓库获取一个产品
publicProductgetProduct()throwsInterruptedException{
synchronized(this){
booleanconsumerRunning=true;//标志消费者线程是否还在运行
ThreadcurrentThread=Thread.currentThread();//获取当前线程
if(currentThreadinstanceofConsumer){
consumerRunning=((Consumer)currentThread).isRunning();
}else{
returnnull;//非消费者不能获取产品
}
//若消费者线程在运行中,但仓库中没有产品了,则消费者线程继续等待
while((front==rear)&&consumerRunning){
wait();
consumerRunning=((Consumer)currentThread).isRunning();
}
//如果消费者线程已经停止运行,则退出该方法,取消获取产品
if(!consumerRunning){
returnnull;
}
//获取当前未被消费的第一个产品
Productproduct=products[front];
System.out.println("Consumer["+currentThread.getName()+"]getProduct:"+product);
//将当前未被消费产品的下标后移一位,如果到了数组末尾,则移动到首部
front=(front+1+CAPACITY)%CAPACITY;
System.out.println("仓库中还没有被消费的产品数量:"+(rear+CAPACITY-front)%CAPACITY);
//通知其他等待线程
notify();
returnproduct;
}
}
//向仓库存储一个产品
publicvoidstorageProduct(Productproduct)throwsInterruptedException{
synchronized(this){
booleanproducerRunning=true;//标志生产者线程是否在运行
ThreadcurrentThread=Thread.currentThread();
if(currentThreadinstanceofProducer){
producerRunning=((Producer)currentThread).isRunning();
}else{
return;
}
//如果最后一个未被消费的产品与第一个未被消费的产品的下标紧挨着,则说明没有存储空间了。
//如果没有存储空间了,而生产者线程还在运行,则生产者线程等待仓库释放产品
while(((rear+1)%CAPACITY==front)&&producerRunning){
wait();
producerRunning=((Producer)currentThread).isRunning();
}
//如果生产线程已经停止运行了,则停止产品的存储
if(!producerRunning){
return;
}
//保存产品到仓库
products[rear]=product;
System.out.println("Producer["+Thread.currentThread().getName()+"]storageProduct:"+product);
//将rear下标循环后移一位
rear=(rear+1)%CAPACITY;
System.out.println("仓库中还没有被消费的产品数量:"+(rear+CAPACITY-front)%CAPACITY);
notify();
}
}
}
packagebook.thread.product;
publicclassTestProduct{
publicstaticvoidmain(String[]args){
Warehousewarehouse=newWarehouse(10);//建立一个仓库,容量为10
//建立生产者线程和消费者
Producerproducers1=newProducer(warehouse,"producer-1");
Producerproducers2=newProducer(warehouse,"producer-2");
Producerproducers3=newProducer(warehouse,"producer-3");
Consumerconsumer1=newConsumer(warehouse,"consumer-1");
Consumerconsumer2=newConsumer(warehouse,"consumer-2");
Consumerconsumer3=newConsumer(warehouse,"consumer-3");
Consumerconsumer4=newConsumer(warehouse,"consumer-4");
//启动生产者线程和消费者线程
producers1.start();
producers2.start();
consumer1.start();
producers3.start();
consumer2.start();
consumer3.start();
consumer4.start();
//让生产者/消费者程序运行1600ms
try{
Thread.sleep(1600);
}catch(InterruptedExceptione){
e.printStackTrace();
}
//停止消费者线程
producers1.stopProducer();
consumer1.stopConsumer();
producers2.stopProducer();
consumer2.stopConsumer();
producers3.stopProducer();
consumer3.stopConsumer();
consumer4.stopConsumer();
}
}
输出结果:
Producer[producer-1]storageProduct:Product-1 仓库中还没有被消费的产品数量:1 Consumer[consumer-2]getProduct:Product-1 仓库中还没有被消费的产品数量:0 Producer[producer-3]storageProduct:Product-3 仓库中还没有被消费的产品数量:1 Producer[producer-2]storageProduct:Product-2 仓库中还没有被消费的产品数量:2 Consumer[consumer-3]getProduct:Product-3 仓库中还没有被消费的产品数量:1 Consumer[consumer-1]getProduct:Product-2 仓库中还没有被消费的产品数量:0 Producer[producer-1]storageProduct:Product-4 仓库中还没有被消费的产品数量:1 Consumer[consumer-4]getProduct:Product-4 仓库中还没有被消费的产品数量:0 Producer[producer-3]storageProduct:Product-6 仓库中还没有被消费的产品数量:1 Producer[producer-2]storageProduct:Product-5 仓库中还没有被消费的产品数量:2 Consumer[consumer-1]getProduct:Product-6 仓库中还没有被消费的产品数量:1 Consumer[consumer-2]getProduct:Product-5 仓库中还没有被消费的产品数量:0 Producer[producer-1]storageProduct:Product-7 仓库中还没有被消费的产品数量:1 Consumer[consumer-3]getProduct:Product-7 仓库中还没有被消费的产品数量:0 Producer[producer-3]storageProduct:Product-8 仓库中还没有被消费的产品数量:1 Producer[producer-2]storageProduct:Product-9 仓库中还没有被消费的产品数量:2 Consumer[consumer-4]getProduct:Product-8 仓库中还没有被消费的产品数量:1 Producer[producer-1]storageProduct:Product-10 仓库中还没有被消费的产品数量:2 Producer[producer-3]storageProduct:Product-11 仓库中还没有被消费的产品数量:3 Producer[producer-2]storageProduct:Product-12 仓库中还没有被消费的产品数量:4 Consumer[consumer-1]getProduct:Product-9 仓库中还没有被消费的产品数量:3 Consumer[consumer-2]getProduct:Product-10 仓库中还没有被消费的产品数量:2 Consumer[consumer-3]getProduct:Product-11 仓库中还没有被消费的产品数量:1 Producer[producer-3]storageProduct:Product-13 仓库中还没有被消费的产品数量:2 Producer[producer-1]storageProduct:Product-14 仓库中还没有被消费的产品数量:3 Producer[producer-2]storageProduct:Product-15 仓库中还没有被消费的产品数量:4 Consumer[consumer-4]getProduct:Product-12 仓库中还没有被消费的产品数量:3 Consumer[consumer-1]getProduct:Product-13 仓库中还没有被消费的产品数量:2 Consumer[consumer-2]getProduct:Product-14 仓库中还没有被消费的产品数量:1 Producer[producer-1]storageProduct:Product-16 仓库中还没有被消费的产品数量:2 Producer[producer-3]storageProduct:Product-17 仓库中还没有被消费的产品数量:3 Producer[producer-2]storageProduct:Product-18 仓库中还没有被消费的产品数量:4
分析:在main方法中建立了一个产品仓库,并未该仓库关联了3个生产者线程和4个消费者线程,启动这些线程,使生产者/消费者模型运作起来,当程序运行1600ms时,所有的生产者停止生产产品,消费者停止消费产品。
生产者线程Product在run方法中没300ms便生产一个产品,并存入仓库;消费者线程Consumer在run方法中没500ms便从仓库中取一个产品。
仓库类Warehouse负责存放产品和发放产品。storageProduct方法负责存储产品,当仓库满时,当前线程进入等待状态,即如果生产者线程A在调用storageProduct方法以存储产品时,发现仓库已满,无法存储时,便会进入等待状态。当存储产品成功时,调用notify方法,唤醒等待的消费者线程。
getProduct方法负责提前产品,当仓库空时,当前线程进入等待状态,即如果消费者线程B在调用getProduct方法以获取产品时,发现仓库空了,便会进入等待状态。当提取产品成功时,调用notify方法,唤醒等待的生产者线程。
以上这篇浅谈java线程中生产者与消费者的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。