生产者与消费者问题是线程同步问题中的一个经典案例,也称作有界缓冲区问题。生产者线程与消费者线程共享一个公共的固定大小的缓冲区。其中生产者将信息放入缓冲区,消费者从缓冲区中取出信息。但是问题在与当缓冲区已满,而生产者还想向其中放入新的数据时候如果不做处理的话就会导致新加入的数据越界。解决的办法是让生产者休眠一段时间,等待消费者从缓冲区中取出一个或者多个数据后再唤醒它/它们。同样的,当消费者试图从缓冲区取出数据而发现缓冲区为空时,消费者休眠一段时间,直达生产者向其中放入一些数据时再唤醒它/它们。
这个不难理解,主要注意线程间的同步和处理好消费者/生产者被唤醒的时刻就可以了(不然的话可能导致生产者还没生产的产品就已经先被消费者吃掉的假现象,这是刚好生产者生产完但是还没输出信息时,线程切换到了消费者哪去了)。
这个不难理解,主要注意线程间的同步和处理好消费者/生产者被唤醒的时刻就可以了(不然的话可能导致生产者还没生产的产品就已经先被消费者吃掉的假现象,这是刚好生产者生产完但是还没输出信息时,线程切换到了消费者哪去了)。
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 == null) continue;
System.out.println("Consumer " + myId + " get: product" + temp);
can.notifyList();//唤醒其他线程
}
try
{
Thread.sleep((int)(Math.random() * time));
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}
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 == null) continue;
System.out.println("Consumer " + myId + " get: product" + temp);
can.notifyList();//唤醒其他线程
}
try
{
Thread.sleep((int)(Math.random() * time));
}catch(Exception e)
{
e.printStackTrace();
}
}
}
}