java 模拟实现消费者和生产者问题
题目要求
用java代码模拟实现:一个人不断往箱子里放苹果,另一个人不断从箱子里取苹果,箱子只能放5个苹果,苹果数量无限。要求不使用java.util.concurrent包中的类。
思路
这道题主要考,java并发编程、Object.wai()、Object.notify()方法的使用、循环队列的使用
1.使用两个线程分别模拟放苹果和取苹果。
2.定义一个类放苹果,类里主要是对一个数组的封装
注意:
Object.wait()及Object.notify()方法的使用,下面是摘自JDK1.6文档
public final void wait() throws InterruptedException在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。 对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用: synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition } 此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。 抛出: IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。 InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
notify
public final void notify()唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。
此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:
通过执行此对象的同步实例方法。
通过执行在此对象上进行同步的 synchronized 语句的正文。
对于 Class 类型的对象,可以通过执行该类的同步静态方法。
一次只能有一个线程拥有对象的监视器。
个人的理解wait()方法即阻塞当前线程,释放锁,直到有人调用notify()或notifyAll()方法来唤醒。注意是对同一对象使用两个方法
notify()主要是唤醒当前对象阻塞的线程。如果有多个线程,随机唤醒一个线程
下面是循环队列的使用
判断循环数组是否为空或满
1.牺牲一个空间
front == rear,即空状态 (rear + 1) % length == front即为满
2.设置一个标志,记录已经放的记录
int count; count == array.length即为满
这里我采用的是第二种方法
线程并发控制可以使用java sychronized进行同步
下面是具体实现
1 public class Test { 2 public static void main(String[] args) { 3 Box box = new Box(); 4 Thread producer = new Thread(new ProduceApple(box)); 5 Thread customer = new Thread(new CustomApple(box)); 6 7 producer.start(); 8 customer.start(); 9 } 10 } 11 12 class Box{ 13 int boxLength = 5; //box容量 14 int buff[] = new int[boxLength]; 15 int putPoint = 0; 16 int getPoint = 0; 17 int boxCount = 0; //box已经放的数量 18 } 19 20 //生产苹果,生产者 21 class ProduceApple implements Runnable{ 22 Box box; 23 24 public ProduceApple(Box box) { 25 this.box = box; 26 } 27 @Override 28 public void run() { 29 while(true){ 30 synchronized (box) { 31 box.putPoint = box.putPoint % box.boxLength; 32 if(box.boxCount == 5){ //没有放苹果的地方,等待消费者消费苹果 33 try { 34 box.wait(); 35 } catch (InterruptedException e) { 36 e.printStackTrace(); 37 } 38 }//if 39 else{ //生产一个苹果放到箱子中 40 box.buff[(++box.putPoint) % box.boxLength] = 1; 41 box.boxCount++; 42 System.out.println("放进一个苹果"); 43 System.out.println("苹果总数:" + box.boxCount); 44 box.notify(); 45 try { 46 Thread.sleep(1000); 47 } catch (InterruptedException e) { 48 e.printStackTrace(); 49 } 50 }//else 51 52 } 53 } 54 55 } 56 } 57 58 //消费苹果,消费者 59 class CustomApple implements Runnable{ 60 Box box; 61 public CustomApple(Box box){ 62 this.box = box; 63 } 64 @Override 65 public void run() { 66 while(true){ 67 synchronized (box) { 68 box.getPoint = box.getPoint % box.boxLength; 69 if(box.boxCount == 0){ //没有可以吃的苹果,等待生产者生产苹果 70 try { 71 box.wait(); 72 } catch (InterruptedException e) { 73 e.printStackTrace(); 74 } 75 }//if 76 else{ //吃掉一个苹果,唤醒生产者 77 box.buff[(++box.getPoint) % box.boxLength] = 0; 78 System.out.println("吃掉一个苹果"); 79 box.boxCount--; 80 System.out.println("苹果总数:" + box.boxCount); 81 box.notify(); 82 83 try { 84 Thread.sleep(1000); 85 } catch (InterruptedException e) { 86 // TODO Auto-generated catch block 87 e.printStackTrace(); 88 } 89 }//else 90 } 91 } 92 93 } 94 95 }
-------------------------------------------------我是分割线-----------------------------------------------
可以使用BlockingQueue来进行模拟
ProducerAndConsumer.java
1 import java.util.concurrent.BlockingQueue; 2 import java.util.concurrent.LinkedBlockingQueue; 3 4 import com.gxf.util.Util; 5 6 /** 7 * 利用BlockingQueue实现生产者和消费者问题 8 * @author Administrator 9 * 10 */ 11 public class ProducerAndConsumer { 12 13 //产品队列 14 private static int queueLength = 5; 15 private static BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>(queueLength); 16 17 18 /** 19 * 模拟生产者 20 * @author Administrator 21 * 22 */ 23 static class ProducerScript implements Runnable{ 24 //生产者名字 25 private String name; 26 27 public ProducerScript(String name) { 28 this.name = name; 29 } 30 31 @Override 32 public void run() { 33 //生产者开始生产 34 while(true){ 35 int product = Util.generateRandomInt(); 36 try { 37 blockingQueue.put(product); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 // System.out.println(name + ":" + product); 42 System.out.println(blockingQueue); 43 try { 44 Thread.sleep(1000); 45 } catch (InterruptedException e) { 46 e.printStackTrace(); 47 } 48 } 49 50 } 51 52 } 53 54 /** 55 * 模拟消费者 56 * @author Administrator 57 * 58 */ 59 static class ConsumerScript implements Runnable{ 60 private String name; 61 62 public ConsumerScript(String name) { 63 this.name = name; 64 } 65 66 @Override 67 public void run() { 68 //消费者开始消费 69 while(true){ 70 int product = -1; 71 try { 72 product = blockingQueue.take(); 73 } catch (InterruptedException e) { 74 e.printStackTrace(); 75 } 76 System.out.println(name + ":" + product); 77 System.out.println(blockingQueue); 78 try { 79 Thread.sleep(2000); 80 } catch (InterruptedException e) { 81 e.printStackTrace(); 82 } 83 } 84 85 } 86 87 } 88 89 /** 90 * 测试程序 91 * @param args 92 */ 93 public static void main(String args[]){ 94 ProducerScript producer = new ProducerScript("生产"); 95 96 ConsumerScript consumer = new ConsumerScript("消费"); 97 98 Thread producerThread = new Thread(producer); 99 // Thread producerThread1 = new Thread(producer); 100 Thread consumerThread = new Thread(consumer); 101 // Thread consumerThread1 = new Thread(consumer); 102 103 producerThread.start(); 104 consumerThread.start(); 105 // consumerThread1.start(); 106 // producerThread1.start(); 107 } 108 }