- 目的
生产者和消费者实例主要是练习synchronized、wait、notify或notifyAll、join等的使用,实际感受他们的用途。这例子自己随意写的,也没想到写得多么完善,只是为了练习。大家将就看看吧,哈哈!
- 食物类
1 package thread.producer.customer; 2 3 public class Food { 4 5 private String name; 6 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 16 }
- 盘子类
1 package thread.producer.customer; 2 3 4 public class Plate { 5 6 //如果是0,表示盘子内没东西 7 private int index; 8 private volatile boolean foodIsFinish = false; 9 10 /** 11 * 向盘子内添加食物,生产者添加食物时,消费者是不能吃食物的,小心被烫到,哈哈 12 * @param food 13 */ 14 public synchronized void addFood(Food food) { 15 index++; 16 System.out.println("盘子内增加了" + food.getName()); 17 notifyAll(); 18 } 19 20 public synchronized void eatFood(String chihuo) throws InterruptedException{ 21 //盘子中没有食物,不代表生产者已经将食物生产完,所以此处要判断生产者是否将食物生产完 22 //只有在盘子没有食物,同时生产者生产完所有食物的时候,该线程才什么都不做,直到线程结束 23 while(index == 0 && !foodIsFinish) { 24 // System.out.println(chihuo + "在等待食物"); 25 wait(); 26 } 27 if(index > 0) { 28 index--; 29 System.out.println("盘子内被"+chihuo+"吃掉"); 30 } 31 } 32 33 public synchronized boolean isEmpty() { 34 return index == 0; 35 } 36 37 public synchronized void setFoodIsFinish(){ 38 this.foodIsFinish = true; 39 } 40 41 public synchronized boolean getFoodIsFinish() { 42 return foodIsFinish; 43 } 44 /** 45 * 等待生产者线程执行完毕,该方法不能为同步方法 46 * @param threads 47 * @throws InterruptedException 48 */ 49 public void waitProducerFinish(Thread producerThread) throws InterruptedException { 50 producerThread.join(); 51 System.out.println("生产者生产食物完毕"); 52 //每个线程结束后,唤醒其他线程,因为有可能出现生产者线程执行完毕,而消费者线程在等待状态,这样就会出现消费者线程一直处于等待状态 53 //这里只能用同步代码块,不能将整个方法进行同步 54 synchronized(this) { 55 setFoodIsFinish(); 56 //notify,notifyAll方法必须在同步方法或同步代码块内,wait方法也一样 57 notifyAll(); 58 } 59 } 60 61 /** 62 * 该方法不能为同步方法 63 * @param threads 64 * @throws InterruptedException 65 */ 66 public void waitCustomerFinish(Thread[] threads) throws InterruptedException { 67 for(int i = 0; i < threads.length; i++) { 68 threads[i].join(); 69 } 70 System.out.println("消费者线程结束"); 71 } 72 }
- 消费者线程
1 package thread.producer.customer; 2 3 public class CustomerThread implements Runnable{ 4 5 private Plate plate; 6 private String chihuo; 7 8 public CustomerThread(Plate plate, String chihuo) { 9 this.plate = plate; 10 this.chihuo = chihuo; 11 } 12 13 @Override 14 public void run() { 15 try { 16 //判断盘子是否为空以及生产者是否已经生产食物完毕 17 //只要在盘子为空或者生产者还有食物生产时,才不跳出循环 18 //这样判断是防止生产者还有食物生产,恰好盘子中无食物,线程退出的不正确情况出现 19 while(!plate.isEmpty() || !plate.getFoodIsFinish()) { 20 // System.out.println(chihuo + "准备吃食物"); 21 plate.eatFood(chihuo); 22 } 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 } 27 28 }
- 生产者线程
1 package thread.producer.customer; 2 3 public class ProducerThread implements Runnable{ 4 5 private Plate plate; 6 7 public ProducerThread(Plate plate){ 8 this.plate = plate; 9 } 10 11 @Override 12 public void run() { 13 String[] foodType = {"apple","banana","pear","plum","grape","drumstick","hamburg","pineapple","staswberry","orange"}; 14 for(int i = 0; i < 100; i++) { 15 int random = (int) (Math.random() * 10); 16 Food food = new Food(); 17 food.setName(foodType[random]); 18 // System.out.println("生产者准备添加食物"); 19 plate.addFood(food); 20 } 21 } 22 }
- 测试类
1 package thread.producer.customer; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Plate plate = new Plate(); 7 Thread t1 = new Thread(new ProducerThread(plate)); 8 Thread t2 = new Thread(new CustomerThread(plate, "吃货1号")); 9 Thread t3 = new Thread(new CustomerThread(plate, "吃货2号")); 10 t1.start(); 11 t2.start(); 12 t3.start(); 13 Thread[] threads = new Thread[2]; 14 threads[0] = t2; 15 threads[1] = t3; 16 try { 17 plate.waitProducerFinish(t1); 18 plate.waitCustomerFinish(threads); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 } 23 24 }