生产者与消费者问题的java示例

原创 2007年10月09日 13:22:00
      生产者与消费者问题是线程同步问题中的一个经典案例,也称作有界缓冲区问题。生产者线程与消费者线程共享一个公共的固定大小的缓冲区。其中生产者将信息放入缓冲区,消费者从缓冲区中取出信息。但是问题在与当缓冲区已满,而生产者还想向其中放入新的数据时候如果不做处理的话就会导致新加入的数据越界。解决的办法是让生产者休眠一段时间,等待消费者从缓冲区中取出一个或者多个数据后再唤醒它/它们。同样的,当消费者试图从缓冲区取出数据而发现缓冲区为空时,消费者休眠一段时间,直达生产者向其中放入一些数据时再唤醒它/它们。


      这个不难理解,主要注意线程间的同步和处理好消费者/生产者被唤醒的时刻就可以了(不然的话可能导致生产者还没生产的产品就已经先被消费者吃掉的假现象,这是刚好生产者生产完但是还没输出信息时,线程切换到了消费者哪去了)。

import java.util.*;

public class ProducerConsumer
...{
    
    
public static void main(String[] args)
    
...{
        Can can 
= new Can(25);
        
        ThreadGroup tgPro 
= new ThreadGroup("Producer");   //生产者线程组
        can.setProducerGroup(tgPro);
        
        
new Thread(tgPro, new Producer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgPro, new Producer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgPro, new Producer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgPro, new Producer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgPro, new Producer(can, (int)(Math.random()*1000))).start();
        
        ThreadGroup tgCus 
= new ThreadGroup("Consumer");  //消费者线程组
        new Thread(tgCus, new Consumer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgCus, new Consumer(can, (int)(Math.random()*1000))).start();
        
new Thread(tgCus, new Consumer(can, (int)(Math.random()*1000))).start();
        
        
    }
    
}


class Can      //用来装产品供生产者放产品和消费者去产品的篮子
...{
    
private  ArrayList list = new ArrayList<String>();
    
private int max;
    
private ThreadGroup tgPro = null;

    Can(
int max)
    
...{
        
this.max = max;
    }

    
    
public void push(String id)       //将产品放进篮子里
    ...{
        
synchronized(list)   //在list上加上对象锁
        ...{    
            
while(list.size() == 6)   //篮子的容量为6,当篮子满了的时候生产者
            ...{                          //必须等待消费者从篮子里取出产品。
                try
                
...{
                    list.wait();
                }
catch(InterruptedException e)
                
...{
                    
                    e.printStackTrace();
                }

                
            }

            
            list.add(id);        
//加入产品
//System.out.println("add one " + id);
        }

    }

        
    
public  String pop()            //从篮子里取出产品
    ...{
        String temp 
= null;
        
        
synchronized(list)          //同样在list上加上把锁,让线程同步
        ...{    
            
while(list.size() == 0)
            
...{                
        
/**//*消费者在这地方要注意,1.如果篮子里没了东西了,它必须等待生产者装。
         *2.但它也不能一味地等,因为当生产者都死掉后,线程队列中可能还有
         * 很多个处于等待状态的消费者,这样将得不到唤醒,那可就天荒地老了。
         *所以要给它限定超时。 
*/
                    
                 
try                        
                
...{                            
                    list.wait(
500);                 
                                     
                    
if(isEmpty())    //如果消费者醒来的时候,篮子里已经空了
                        return null;  //并且生产者都死掉了,那么只能返回null      
                                   
                }
catch(InterruptedException e)
                
...{
                    e.printStackTrace();
                }

            }
    
                
            temp 
= (String)list.remove(list.size() - 1); //取出产品
            --max;            
//System.out.println("remove  one " + temp);                
            return temp;
        }
    
        
    }

    
    
public  boolean isEmpty()  
    
...{
        
if( (tgPro.activeCount() == 0)//如果生产者都死掉了
              && (list.isEmpty())       //并且篮子里没东西了,那么
                  && (max == 0)  )        //意味篮子将永远空了。
           return true;
        
        
return false;
    }

    
    
public void notifyList()  //将唤醒作为一个同步方法独立出来,
    ...{                         //这样消费者或消费者在取出或者加入产品后在没唤醒
        synchronized(list)    //其他线程之前可以做点小动作。
        ...{
            list.notifyAll();
        }

    }

    
    
public void setProducerGroup(ThreadGroup tgPro)//设置消费者的线程组
    ...{
        
this.tgPro = tgPro;
    }

}



class Producer implements Runnable   //生产者类
...{    
    
private static int ProducerID = 0;
    
private static int productID = 0;
    
private  int myId;
    
private Can can = null;
    
private int time;
    
    Producer(Can can, 
int time)
    
...{
        
this.myId = ProducerID++;
        
this.can = can;
        
this.time = time;
    }

    
    
public void run()
    
...{
        
for(int i=0; i<5; i++)
        
...{
            can.push(
new String(""+myId + "" + productID));//加入产品,    
            System.out.println("Produce " + myId + " create: " + productID);//并且
            ++productID;                                      //做点小动作
        
            can.notifyList(); 
//唤醒其他线程,这样才不会出现生产者还没生产
                              
//但是已经被消费者吃掉的假现象,其实是生产者
                              
//已经生产了,但是还没输出信息的时候线程就被切换到
                              
//消费者那里去了。
            try
            
...{
                Thread.sleep((
int)(Math.random() * time));//放大效果
                    
            }
catch(Exception e)
            
...{
                e.printStackTrace();
            }

        }

            
System.out.println(
"--------------Producer " + myId + "closed----------------");    
    }

    
}


class Consumer implements Runnable  //消费者类
...{    
    
private static int ConsumerID = 0;
    
private int myId;
    
private Can can = null;
    
private int time;
    
    Consumer(Can can, 
int time)
    
...{
        
this.myId = ConsumerID++;
        
this.can = can;
        
this.time = time;
    }

        
    
public void run()
    
...{
        String temp 
= null;
        
        
while(true)
        
...{
            
if(can.isEmpty()) //如果篮子里没了,生产者死了,跳出循环,结束线程
            ...{
System.out.println(
"-------------------Consumer " + myId + "closed-----------");
                
break;
            }

            
else 
            
...{        
                    temp 
= can.pop();
                    
if(temp == nullcontinue;    
                    System.out.println(
"Consumer " + myId + "  get: product" + temp);
                    
                    can.notifyList();
//唤醒其他线程        
            }

                
            
try
            
...{            
                Thread.sleep((
int)(Math.random() * time));
                    
            }
catch(Exception e)
            
...{
                e.printStackTrace();
            }

        }

    }

}
 

多线程经典案例——生产者/消费者问题的Java实现与详解

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共...
  • shengwusuoxi
  • shengwusuoxi
  • 2014年04月01日 12:37
  • 2586

生产者消费者问题的java实现

生产者和消费者是多线程经典的问题,生产者和消费者问题的核心是同步的问题,同步问题的核心是要保证同一个资源被多个线程并发访问时的完整性,常用的方法是采用信号或加锁机制,保证资源在任一时刻只能被一个线程访...
  • longshengguoji
  • longshengguoji
  • 2014年11月29日 19:44
  • 3533

Java多线程之简单生产者和消费者例子

一,在本例子中,有三个类,dataStore(存放数据类),consumer(消费者),producer(生产者)。 二,看源码例子: 类dataStore: import java.lang....
  • ganpengjin1
  • ganpengjin1
  • 2015年04月18日 15:13
  • 1820

java多线程生产者消费者问题示例

  • 2013年12月30日 11:22
  • 2KB
  • 下载

操作系统课程设计——“生产者消费者”问题的模拟仿真 Java 图形界面动态演示(源码+课设报告)

  • 2018年01月16日 15:23
  • 318KB
  • 下载

生产者消费者问题 Java

  • 2014年07月07日 10:36
  • 9KB
  • 下载

JAVA死锁and生产者消费者问题

  • 2012年06月02日 07:27
  • 1KB
  • 下载

java实现生产者消费者商品问题

  • 2015年08月12日 17:49
  • 10KB
  • 下载

java生产者与消费者问题

  • 2014年11月06日 22:14
  • 10KB
  • 下载

生产者消费者问题代码示例

生产者消费者问题是一个经典的并发实例,因为项目需要代码优化实现程序并行,因此直接学习这一部分知识拿来用作代码的优化,也是边学习边理解。程序菜鸟一只,只希望尽快入门,早点得道。 这段代码是从别人处偷来...
  • crazyeden
  • crazyeden
  • 2017年07月14日 20:48
  • 233
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:生产者与消费者问题的java示例
举报原因:
原因补充:

(最多只允许输入30个字)