码迷,mamicode.com
首页 > 编程语言 > 详细

多线程生成者消费者问题改进

时间:2015-08-08 12:16:22      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

常用的解决方案中,卖完饭了,会采用Object类的notiryAll的方式唤醒所有线程,这样做其实是浪费和低效的,因为唤醒所有线程的时候,会把卖饭的线程也唤醒。现在换用Lock锁的方式来解决,一个Lock可以new多个Condition出来,通过condition来唤醒对应condition上等待的线程。

卖饭类:

package com.sniper.thread.lock.domain;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * 餐馆,负责卖饭
 * @author audaque
 *
 */
public class Restaurant implements Runnable {
 
 public void sale() {
  while(true) {
   MyLock.MY_LOCK.lock();
   List<Food> foods = Window.foods;
   if(foods.size() > 0) {
    Food food = foods.get(0);
    System.out.println(Thread.currentThread().getName() + "卖了第" + food.getId() + "号食物。。。");
    
    /*try {
     TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }*/
    
    //卖出一份,减少一份
    foods.remove(0);
    
    //MyLock.CON.signal();//随机唤醒等待中的一条线程
    MyLock.COOK_CON.signalAll();;//唤醒等待中全部线程
   } else {
    System.out.println(Thread.currentThread().getName() + ":食物卖完了,我休息了。。。");
    
    try {
     MyLock.R_CON.await();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   MyLock.MY_LOCK.unlock();
  }
 }
 @Override
 public void run() {
  sale();
 }
 
}

做饭类:

package com.sniper.thread.lock.domain;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
 * 厨师,负责做饭
 * @author audaque
 *
 */
public class Cook implements Runnable {
 
 public static int num = 1;
 
 public void make() {
  while(true) {
   MyLock.MY_LOCK.lock();
   List<Food> foods = Window.foods;
   if(foods.size() <= Window.max_num) {
    Food food = new Food(num);
    foods.add(food);
    
    System.out.println(Thread.currentThread().getName() + "做了第" + food.getId() + "号食物。。。");
    
    
    /*try {
     TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }*/
    
    num++;
    
    /*
     * notify随机唤醒一条线程,容易产生问题
     * 假设三个做饭的,三个卖饭的
     * 在某一瞬间三个卖饭的都处于等待,两个做饭的也处于等待
     * 最后一个做饭的做好一份饭之后,随机唤醒其中一条,假如唤醒的是做饭线程,
     * 此时,两条醒着的做饭线程判断foods.size() > Window.max_num(1)
     * 然后两条做饭线程也休息了,此时,六条线程都会处于等待状态,没人会唤醒他们
     * 也就是死锁
     */
    //MyLock.CON.signal();//随机唤醒等待中的一条线程
    MyLock.R_CON.signalAll();;//唤醒等待中全部线程
   } else {
    System.out.println(Thread.currentThread().getName() + ":窗口放满食物了,我休息了。。。");
    try {
     MyLock.COOK_CON.await();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   MyLock.MY_LOCK.unlock();
  }
 }
 @Override
 public void run() {
  make();
 }
 
}

窗口,从窗口取饭卖,做完饭往窗口放:

package com.sniper.thread.lock.domain;
import java.util.ArrayList;
import java.util.List;
/**
 * 窗口,厨师做完饭往窗口放,餐馆从窗口拿饭卖
 * @author sniper
 *
 */
public class Window {
 
 public static List<Food> foods = new ArrayList<Food>();
 
 //窗口最大容纳食物数量
 public static int max_num = 1;
 
}

食物类:

package com.sniper.thread.lock.domain;
/**
 * 食物
 * @author sniper
 *
 */
public class Food {
 
 private int id;
 
 private String name;
 public Food(int id) {
  super();
  this.id = id;
 }
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
}

App:

package com.sniper.thread.lock.domain;
public class App {
 
 public static void main(String[] args) {
  Cook cook = new Cook();
  //三条做饭线程
  for(int i=0; i<3; i++) {
   new Thread(cook).start();
  }
  
  Restaurant r = new Restaurant();
  //十条卖饭线程
  for(int i=0; i<3; i++) {
   new Thread(r).start();
  }
 }
 
}

锁类:

package com.sniper.thread.lock.domain;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyLock {
 
 public static final Lock MY_LOCK = new ReentrantLock();
 
 public static final Condition R_CON = MY_LOCK.newCondition();
 
 public static final Condition COOK_CON = MY_LOCK.newCondition();
 
 private MyLock() {}
 
}

多线程生成者消费者问题改进

标签:

原文地址:http://my.oschina.net/sniperLi/blog/489425

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!