标签:
常用的解决方案中,卖完饭了,会采用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