第二十一章:并发(下)
来源:互联网 发布:淘宝美工基础教程 编辑:程序博客网 时间:2024/06/01 19:53
新类库中的构件
CountDownLatch
- 可以向CountDownLatch对象设置一个初始计数值,任何对象在这个对象上调用await()方法都将阻塞,直至这个计数值为0(如果一开始就是0那就不用等待)。我们通过其他任务在这个对象上调用countDown()来缩小这个计数值(最多减到0)。这个构件的意义就是设置一些任务必须在n个任务都完成的情况下才可以执行。
import java.util.Random;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CountDownLatchDemo { static final int SIZE = 100; public static void main(String args[]) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); CountDownLatch latch = new CountDownLatch(SIZE); for (int i=0; i<10; i++) { exec.execute(new WaitingTask(latch)); } for (int i=0; i<SIZE; i++) { exec.execute(new TaskPortion(latch)); } System.out.println("Launched all tasks"); exec.shutdown(); }}class TaskPortion implements Runnable { private static int counter = 1; private static Random rand = new Random(47); private final int id = counter++; private final CountDownLatch latch; public TaskPortion(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { Thread.sleep(rand.nextInt(2000));//模拟一个任务需要时间去完成 System.out.println(this + "completed"); latch.countDown(); System.out.println(latch.getCount()); } catch (InterruptedException e) {} } public String toString() { return String.format("%-3d ", id); }}class WaitingTask implements Runnable { private static int counter = 1; private final int id = counter++; private final CountDownLatch latch; public WaitingTask(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { latch.await(); System.out.println("Latch barrier passed for " + this); } catch (InterruptedException e) { System.out.println(this + "interrupted"); } } public String toString() { return String.format("WaitingTask %-3d ", id); }}
- 程序运行后,10个WaitingTask任务将等待,直到100个TaskPortion全部执行完毕再开始执行。
CyclicBarrier
- CyclicBarrier适用于你希望创建一组任务,它们并行执行,然后在进行下一个步骤之前等待,直至所有任务都完成。它使得所有的并行任务都将在栅栏处列队,因此可以一致地向前运动。它与CountDownLatch的区别是,后者是只触发一次的事件,而它可以多次重用。下面是我模仿书上赛马的程序写的一个关于加载的程序:
import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 模拟LOL要10个人才能开始游戏 * 每次必须满10个人一起加载一次,当加载量都为100时,游戏开始 */public class PlayGame { public static ExecutorService exec = Executors.newCachedThreadPool(); public static List<Player> players = new ArrayList<Player>(); public static CyclicBarrier barrier = new CyclicBarrier(10, new StartGame(players)); static { for (int i=0; i<10; i++) { Player p = new Player(); players.add(p); System.out.println("player" + p.id + " 准备进入游戏"); } } public static void main(String args[]) { for (int i=0; i<10; i++) exec.execute(new LoadGame(players.get(i), barrier)); }}class Player { private static int counter = 1; private int percentage = 0; public final int id = counter++; public void addPercentage(int nextInt) { percentage += nextInt; System.out.println("player" + id + " 加载了" + percentage + "%"); } public int getPercentage() {return percentage;}}class LoadGame implements Runnable { private static Random rand = new Random(47); private final CyclicBarrier barrier; private final Player player; public LoadGame(Player player, CyclicBarrier barrier) { this.player = player; this.barrier = barrier; } @Override public void run() { try { while (!Thread.interrupted()) { if (player.getPercentage() < 96) { player.addPercentage(rand.nextInt(5) + 1);//1~5 } else { player.addPercentage(100 - player.getPercentage()); } barrier.await(); } } catch (InterruptedException e) { System.out.println(); } catch (BrokenBarrierException e) { throw new RuntimeException(e); } System.out.println("player" + player.id + " 开始游戏"); }}class StartGame implements Runnable { private List<Player> players; public StartGame(List<Player> players) { this.players = players; } @Override public void run() { System.out.println("服务器集中加载一次完毕!"); int i = 0; for (Player player : players) { if (player.getPercentage() < 100) { break; } i++; } if (i == players.size()) { System.out.println("比赛开始!"); PlayGame.exec.shutdownNow(); } }}
DelayQueue
- 这个是一个延迟队列,他也是线程安全的,存放的泛型类型必须实现Delayed接口。当其实它和优先级队列挺像的,下面是一个例子:
import java.util.*;import java.util.concurrent.*;class DelayedTask implements Runnable, Delayed { private final long delay; private final long runtime; private final int id; public DelayedTask(int id, long delay) { this.id = id; this.delay = delay; this.runtime = System.currentTimeMillis() + delay; } @Override public int compareTo(Delayed o) { DelayedTask t = (DelayedTask) o; long result = this.runtime - t.runtime; if (result > 0) return 1; else if (result < 0) return -1; else return 0; } @Override public long getDelay(TimeUnit unit) { return unit.convert(runtime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public void run() { System.out.println(id + " run! delay=" + delay); }}class DelayedTaskConsumer implements Runnable { private DelayQueue<DelayedTask> q; public DelayedTaskConsumer(DelayQueue<DelayedTask> q) { this.q = q; } @Override public void run() { try { while (!Thread.interrupted()) { q.take().run();//只是run 没有start } } catch (InterruptedException e) {} finally { System.out.println("finish!"); } }}public class DelayQueueDemo { public static void main(String[] args) throws Exception { Random rand = new Random(47); ExecutorService exec = Executors.newCachedThreadPool(); DelayQueue<DelayedTask> queue = new DelayQueue<DelayedTask>(); for (int i=0; i<20; i++) { queue.put(new DelayedTask(i + 1, rand.nextInt(5000))); } exec.execute(new DelayedTaskConsumer(queue)); Thread.sleep(5000); exec.shutdownNow(); }}
PriorityBlockingQueue
- 如果你看过之前集合中的PriorityQueue, 再结合BlockingQueue的用法,我想这个可以省略了。
ScheduledExecutor
- 这是一种定时器的方式,类似于js中的setTimeout()和setInterval()。直接看例子吧。
import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class ScheduleThreadPoolDemo { private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss SSS"); public static void main(String args[]) { ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(5); exec.schedule(new Mission(), 1000, TimeUnit.MILLISECONDS); //这个是根据上一次开始时间去延迟1000毫秒 exec.scheduleAtFixedRate(new Mission(), 2000, 1000, TimeUnit.MILLISECONDS); //这个是根据上一次结束时间去延迟1000毫秒 exec.scheduleWithFixedDelay(new Mission(), 3000, 1000, TimeUnit.MILLISECONDS); //用法一致 其实返回的是同一种类型 //ScheduledExecutorService exec2 = Executors.newScheduledThreadPool(5); //exec2.schedule(command, delay, unit) //exec2.scheduleAtFixedRate(command, initialDelay, period, unit) //exec2.scheduleWithFixedDelay(command, initialDelay, delay, unit) } static class Mission implements Runnable { private static int count = 0; private final int id = ++count; @Override public void run() { System.out.println(id + " run in:" + sdf.format(new Date(System.currentTimeMillis()))); } }}
Semaphore
- 正常的锁(locks或synchronized)在任何时刻都只允许一个任务访问一项资源。而计数信号量允许n个任务同时访问这个资源(这个资源可能是一个对象池)。
import java.lang.reflect.Array;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class SemaphoreDemo { private static final int poolsize = 3; public static void main(String args[]) throws Exception { Pool<TestObj> pool = new Pool<TestObj>(TestObj.class, poolsize); ExecutorService exec = Executors.newCachedThreadPool(); for (int i=0; i<poolsize; i++) { exec.execute(new Hold<TestObj>(pool, (i + 1) * 1000)); } for (int i=0; i<poolsize; i++) { exec.execute(new Hold<TestObj>(pool, 500)); } exec.shutdown(); }}class Hold<T> implements Runnable { private static int count; private final int id = ++count; private final Pool<T> pool; private final long time; public Hold(Pool<T> pool, long time) { this.pool = pool; this.time = time; } public void run() { try { T task = pool.checkOut(); System.out.println("Thread" + id + " get: " + task); Thread.sleep(time); System.out.println("Thread" + id + " release: " + task); pool.checkIn(task); System.out.println("Thread" + id + " release success!"); } catch (InterruptedException e) { e.printStackTrace(); } }}class TestObj { private static int count; private final int id = ++count; public int getId() { return id; } public String toString() { return "resourceId:" + id; }}class Pool<T> { private Semaphore available; private int size; private T[] data; private boolean[] checkOut; @SuppressWarnings("unchecked") public Pool(Class<T> clazz, int size) throws InstantiationException, IllegalAccessException { available = new Semaphore(size, true); this.size = size; checkOut = new boolean[size]; data = (T[]) Array.newInstance(clazz, size); for (int i=0; i<size; i++) { data[i] = clazz.newInstance(); } } public T checkOut() throws InterruptedException { available.acquire();//请求一个许可证,如果没有则等待。 return getItem(); } public boolean checkIn(T x) throws InterruptedException { if (releaseItem(x)) { available.release();//释放一个许可证 return true; } return false; } private synchronized T getItem() { for (int i=0; i<size; i++) { if (!checkOut[i]) { checkOut[i] = true; return (T) data[i]; } } return null; } private synchronized boolean releaseItem(T x) { for (int i=0; i<size; i++) { if (data[i] == x) { if (checkOut[i]) { checkOut[i] = false; return true; } return false; } } return false; }}--------------运行结果:Thread1 get: resourceId:1Thread2 get: resourceId:2Thread3 get: resourceId:3Thread1 release: resourceId:1Thread1 release success!Thread4 get: resourceId:1Thread4 release: resourceId:1Thread4 release success!Thread5 get: resourceId:1Thread2 release: resourceId:2Thread2 release success!Thread6 get: resourceId:2Thread5 release: resourceId:1Thread5 release success!Thread6 release: resourceId:2Thread6 release success!Thread3 release: resourceId:3Thread3 release success!
Exchanger
- Exchanger是在两个任务之间交换对象的栅栏。他们各自拥有一个对象,调用exchange()后(可能进入阻塞,等待对方调用这个方法),会得到对方的对象。Exchanger的应用场景是:一个任务在创建对象,这些对象的生产代价很高昂。而另外一个任务在消费这些对象(然后将空容器返回给生产者)。听起来和普通的生产者消费者差不多,区别就是可以在消费这个对象的同时创建新的对象(因代价高昂需尽早创建,且因为调用exchange()会阻塞,也不必担心浪费空间)。可以想象这么一个场景:一共有两个水桶,一个人负责在井边打水,一个人负责拿着装满水的桶去装进自家水库。要是只有一个水桶,打水的和倒水的难免得互相等待。如果有两个桶,倒水的每次只要将空桶交给打水的,然后直接拿走装满水的桶,那么就可以使效率提高。
import java.util.List;import java.util.concurrent.*;public class ExchangerDemo { public static void main(String args[]) { Exchanger<List<Integer>> changer = new Exchanger<List<Integer>>(); ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ExchangerProducer(changer)); exec.execute(new ExchangerConsumer(changer)); exec.shutdown(); }}class ExchangerProducer implements Runnable { //这个类型可以在遍历的时候,remove。因为是交换对象,所以生产者的类型一般都和消费者一致 private List<Integer> holder = new CopyOnWriteArrayList<>(); private int begin = 0; private Exchanger<List<Integer>> changer; public ExchangerProducer(Exchanger<List<Integer>> changer) { this.changer = changer; } @Override public void run() { try { while (!Thread.interrupted()) { for (int i=begin; i<begin+10; i++) { holder.add(i); } begin = begin + 10; System.out.println("producer 前 " + holder); holder = changer.exchange(holder); System.out.println("producer 后 " + holder); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } }}class ExchangerConsumer implements Runnable { private List<Integer> holder = new CopyOnWriteArrayList<>();//这个类型可以在遍历的时候,remove private Exchanger<List<Integer>> changer; public ExchangerConsumer(Exchanger<List<Integer>> changer) { this.changer = changer; } @Override public void run() { try { while (!Thread.interrupted()) { System.out.println("consumer 前 " + holder); holder = changer.exchange(holder); System.out.println("consumer 后 " + holder); for (Integer i : holder) { //holder.remove(i);//注释掉可以看到交换场景 } } } catch (InterruptedException e) { e.printStackTrace(); } }}
仿真
银行出纳员仿真
- 看这个名字差不多就知道是什么用处,代码有注释。期间遇到了怪异的问题(出队不是最大值),后来看了看以前的文章就明白了。
import java.util.*;import java.util.concurrent.*;public class BankTellerSimulation { private static final int MAX_LINE_SIZE = 50; private static final int ADJUSTMENT_PERIOD = 1000; public static void main(String args[]) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); CustomerLine customers = new CustomerLine(MAX_LINE_SIZE); exec.execute(new CustomerGenerator(customers)); exec.execute(new TellerManager(exec, customers, ADJUSTMENT_PERIOD)); System.in.read(); exec.shutdownNow(); }}//顾客class Customer { private final int serviceTime;//此值模拟用户的服务时间 public Customer(int st) { serviceTime = st; } public int getServiceTime() { return serviceTime; } public String toString() { return "[" + serviceTime + "]"; }}//排号队伍class CustomerLine extends ArrayBlockingQueue<Customer> { public CustomerLine(int capacity) { super(capacity); } public String toString() { if (isEmpty()) { return "[Empty]"; } StringBuilder result = new StringBuilder(); for (Customer cus : this) { result.append(cus); } return result.toString(); }}//模拟有顾客来办业务class CustomerGenerator implements Runnable { private static Random random = new Random(47); private CustomerLine customers; public CustomerGenerator(CustomerLine cl) { customers = cl; } @Override public void run() { try { while (!Thread.interrupted()) { Thread.sleep(random.nextInt(300)); //不定期的来客户,其服务时间也不定 customers.put(new Customer(random.nextInt(1000))); } } catch (InterruptedException e) { System.out.println("CustomerGenerator 程序中断"); } System.out.println("CustomerGenerator 程序停止"); }}//出纳员服务线程class Teller implements Runnable, Comparable<Teller>{ private static int counter = 0; private final int id = counter++; private int customerServed = 0;//已服务人数 private CustomerLine customers; private boolean servingCustomerLine = true; public Teller(CustomerLine cl) { customers = cl; } @Override public void run() { try { while (!Thread.interrupted()) { Customer customer = customers.take();//呼叫客户,如果没有则阻塞 Thread.sleep(customer.getServiceTime());//模拟进行服务 //在服务期间TellerManager线程可能判断出此时不再需要那么多人了,servingCustomerLine被置为false synchronized (this) { customerServed++;//服务人数加1 //如果此时TellerManager线程已经允许我们释放自己,那么我们就wait()。 //用while是因为唤醒的可能是别人而不是自己 while (!servingCustomerLine) wait();//wait期间TellerManager线程可能又将其设置为true } } } catch (InterruptedException e) { System.out.println("Teller 程序中断"); } System.out.println("Teller 程序停止"); } //没人来了就等待,或者说去做别的事情去 public synchronized void doSomethingElse() { //customerServed = 0;//书上有这句代码,我觉得没有必要,因为讲道理是可以累积的 servingCustomerLine = false;//将这个出纳员的状态调整为休息状态 //吃饭聊天打豆豆...爱干嘛干嘛 } //有人来了就开始服务 public synchronized void serveCustomerLine() { assert !servingCustomerLine : "服务已经在运行!:" + this; servingCustomerLine = true; notifyAll(); } //用于线程资源合理分配,干活多的出纳员优先出队去干别的事情。比较期间不允许对customerServed进行修改,所以是synchronized的。 public synchronized int compareTo(Teller o) { return customerServed - o.customerServed; } //出纳员编号 public String toString() { return "T" + id + "(" + customerServed + ")"; }}//出纳员控制系统class TellerManager implements Runnable { private ExecutorService exec; private CustomerLine customers; //了解PriorityQueue的应该知道,当poll或者offer一个值时,它并不会遍历所有的队列值 //此处书上使用PriorityQueue是不对的,因为customerServed在中途进行了变化,为了使结果正确我将重写poll方法。 //private PriorityQueue<Teller> workingTellers = new PriorityQueue<Teller>(); private PriorityQueue<Teller> workingTellers = new MyPriorityQueue<Teller>(); //这个队列也不能这么写,也应该选择最小的出来,不过因为这个队列里的customerServed不会变化,所以可以直接使用PriorityQueue //其实就算改成PriorityQueue也不是特别严谨,要注意到customerServed++基本上是在放入队列后发生的。不过最多差1位,关系不是很大 //这里也体现了要想正确使用并发编程真的很难 //private Queue<Teller> tellerDoingOhterThings = new LinkedList<Teller>(); private Queue<Teller> tellerDoingOhterThings = new PriorityQueue<Teller>(); private int adjustmentPeriod;//调整时间间隔 public TellerManager(ExecutorService e, CustomerLine cl, int adjustmentPeriod) { exec = e; customers = cl; this.adjustmentPeriod = adjustmentPeriod; newOneTeller(); } public void adjustTellerNumber() { //如果顾客太多了,就增加一个出纳员 if (customers.size() / workingTellers.size() > 2) { if (tellerDoingOhterThings.size() > 0) { Teller teller = tellerDoingOhterThings.poll();//选出一个最小值 teller.serveCustomerLine();//从空闲队列中取出一个出纳员进行服务,必须持有teller的锁 workingTellers.offer(teller); return; } newOneTeller(); return; } //如果工作的人太多了,就释放一个出纳员 if (workingTellers.size() > 1 && customers.size() / workingTellers.size() < 2) { reassingOneTeller(); } //如果没有要服务的客户,则递减到一个出纳员 if (customers.size() == 0) { while (workingTellers.size() > 1) { reassingOneTeller(); } } } //分配一个出纳员 private void newOneTeller() { Teller teller = new Teller(customers); exec.execute(teller); workingTellers.add(teller); } //释放一个出纳员 private void reassingOneTeller() { Teller teller = workingTellers.poll();//使用了重写的方法,选出了一个最大值 teller.doSomethingElse();//必须持有teller的锁 tellerDoingOhterThings.offer(teller); } @Override public void run() { try { while (!Thread.interrupted()) { Thread.sleep(adjustmentPeriod); adjustTellerNumber();//因为只有一个线程,所以不需要加锁 System.out.print(customers + " {工作中: "); for (Teller teller : workingTellers) { System.out.print(teller + " "); } System.out.print(", 休息中: "); for (Teller teller : tellerDoingOhterThings) { System.out.print(teller + " "); } System.out.println("}"); } } catch (InterruptedException e) { System.out.println("TellerManager 程序中断"); } System.out.println("TellerManager 程序结束"); }}//修改poll方法的优先级队列class MyPriorityQueue<T> extends PriorityQueue<T> { @Override public T poll() { if (isEmpty()) return null; T[] data = (T[]) toArray(); T max = data[0]; for (int i = 1; i < data.length; i++) { if (((Comparable<T>) max).compareTo(data[i]) < 0) { max = data[i]; } } remove(max); return max; }}
饭店仿真
import java.util.*;import java.util.concurrent.*;public class RestaurantWithQueues { public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(); Restaurant rest = new Restaurant(exec, 5, 2);//5个小二,两个厨师 exec.execute(rest);//开业啦 Thread.sleep(10000);//开十秒就关门了 exec.shutdownNow();//所有人都赶出去,最可怕的是连厨师小二都不让干活了 }}//可以假想成一份菜单,不过是一份菜的指派菜单class Order { private static int counter = 0; private final int id = counter++; private final Customer customer;//顾客 private final WaitPerson waitPerson;//服务的小二 private final Food food;//所需的菜肴 public Order(Customer customer, WaitPerson waitPerson, Food food) { this.customer = customer; this.waitPerson = waitPerson; this.food = food; } public Food item() { return food; } public Customer getCustomer() { return customer; } public WaitPerson getWaitPerson() { return waitPerson; } public String toString() { return "Order: " + id + " item: " + food + " for: " + customer + " served by: " + waitPerson; }}//可以假想成一份成品菜肴,可以吃的那种class Plate { private final Order order;//对应的菜单 private final Food food;//可以吃的菜肴,这里用枚举类代替 public Plate(Order order, Food food) { this.order = order; this.food = food; } public Order getOrder() { return order; } public Food getFood() { return food; } public String toString() { return food.toString(); }}//顾客 线程,任务是给小二下单,然后等待小二送来菜肴class Customer implements Runnable { private static int counter = 0; private final int id = counter++; private final WaitPerson waitPerson;//该服务的小二 private static Random rand = new Random(47); private SynchronousQueue<Plate> plateSetting = new SynchronousQueue<Plate>();//只有take和put同时完成后,才能进行下次take()和put(),否则任一操作都会阻塞 public Customer(WaitPerson wp) { waitPerson = wp; } public void deliver(Plate p) throws InterruptedException { plateSetting.put(p);//从小二的手中接过菜肴(put->take 组成一个过程) } @Override public void run() { Food[] foods = Food.choose();//顾客随机选取了一组菜肴 System.out.println(this + "下单:" + Arrays.toString(foods)); try { if (!Thread.interrupted()) { for (Food food : foods) { waitPerson.placeOrder(this, food);//一个一个上 System.out.println(this + "eating " + plateSetting.take());//等待直到 从小二的手中接过菜肴(put->take组成一个过程)。 } } } catch (InterruptedException e) { System.out.println(this + "waiting 中断"); } System.out.println(this + "吃完了"); } public String toString() { return "Customer " + id + " "; }}//小二 线程,任务是拿出已经做好并且是分发给自己的菜肴,然后送给这个顾客class WaitPerson implements Runnable { private static int counter = 0; private final int id = counter++; private final Restaurant restaurant; BlockingQueue<Plate> filledOrders = new LinkedBlockingQueue<Plate>();//小二收到的已经完成的菜肴 public WaitPerson(Restaurant r) { restaurant = r; } public void placeOrder(Customer cust, Food food) { try { restaurant.orders.put(new Order(cust, this, food));//添加一份新订单 } catch (InterruptedException e) { System.out.println(this + " placeOrder 中断"); } } public void run() { try { while (!Thread.interrupted()) {//压榨他!不许休息 Plate plate = filledOrders.take();//拿出包装好的菜肴 System.out.println(this + "received " + plate + " delivering to " + plate.getOrder().getCustomer());//准备丢给那个顾客 plate.getOrder().getCustomer().deliver(plate);//让顾客接收这个菜肴 } } catch (InterruptedException e) { System.out.println(this + " 中断"); } System.out.println(this + " 结束"); } public String toString() { return "WaitPerson " + id + " "; }}//厨师 线程,任务是从订单队列中拿出订单(Order),做完(Plate)并丢给相应的小二class Chef implements Runnable { private static int counter = 0; private final int id = counter++; private final Restaurant restaurant; private static Random rand = new Random(47); public Chef(Restaurant r) { restaurant = r; } public void run() { try { while (!Thread.interrupted()) {//压榨他!不许休息 Order order = restaurant.orders.take();//厨师从菜单中拿出Order,也就是订单 Food item = order.item();//知道要做什么菜 Thread.sleep(rand.nextInt(500));//假设花的时间不定 Plate plate = new Plate(order, item);//成品菜肴完成了 order.getWaitPerson().filledOrders.put(plate);//丢给这个小二 } } catch (InterruptedException e) { System.out.println(this + " 中断"); } System.out.println(this + " 结束"); } public String toString() { return "Chef " + id + " "; }}//饭店 线程 负责接待顾客,分配小二class Restaurant implements Runnable { private List<WaitPerson> waitPersons = new ArrayList<WaitPerson>(); private List<Chef> chefs = new ArrayList<Chef>(); private ExecutorService exec; private static Random rand = new Random(47); BlockingQueue<Order> orders = new LinkedBlockingQueue<Order>();//相当于订单表 public Restaurant(ExecutorService exec, int nWaitPersons, int nChefs) { this.exec = exec; for (int i = 0; i < nWaitPersons; i++) { WaitPerson waiter = new WaitPerson(this); waitPersons.add(waiter); exec.execute(waiter); } for (int i = 0; i < nChefs; i++) { Chef chef = new Chef(this); chefs.add(chef); exec.execute(chef); } } @Override public void run() { try { while (!Thread.interrupted()) {//我就是不关门 WaitPerson wp = waitPersons.get(rand.nextInt(waitPersons.size()));//随机选取一个小二 Customer c = new Customer(wp);//假设来了一个客户,并把这个客户分给这个小二 exec.execute(c);//让这个客户自行下单 Thread.sleep(100);//模拟0.1秒来个客户 } } catch (InterruptedException e) { System.out.println("Restaurant 中断"); } System.out.println("Restaurant 结束"); }}enum Food { 南汇水蜜桃, 三林糖酱瓜, 佘山兰笋, 松江回鳃鲈, 枫泾西蹄, 城隍庙五香豆, 崇明金瓜, 南桥乳腐, 高桥松饼, 嘉定大白蒜; private static Random rand = new Random(47); public static Food[] choose() { Food[] allfoods = values(); int count = allfoods.length;//10 for (int i = 0; i < count - 1; i++) { //打乱顺序 int index = rand.nextInt(count); Food temp = allfoods[i]; allfoods[i] = allfoods[index]; allfoods[index] = temp; } int need = rand.nextInt(allfoods.length / 2) + 1; Food[] foods = new Food[need]; int beginIndex = rand.nextInt(count - need + 1); System.arraycopy(allfoods, beginIndex, foods, 0, need); return foods; }}
分发工作
性能调优
比较各类互斥技术
免锁容器
乐观锁
比较各类Map实现
乐观加锁
ReadWriteLock
活动对象
小结
- 还有这么多的内容,我就不写了。。想开启下一本书,这个就先这样吧。以后想起来了再回来更新。
阅读全文
0 0
- 第二十一章:并发(下)
- 第二十一章:并发(中)
- 第二十一章:并发(上)
- 《Java编程思想》学习笔记(第二十一章):并发
- 《java编程思想》第二十一章 并发
- Thinking in Java——第二十一章-( 一)并发&Java中的多线程
- 第二十一章 泛型(generic)
- Thinking in Java学习笔记 第二十一章:并发
- 第二十一章
- 第二十一章 模板方法(Template Method)
- 第二十一章 条件语气
- 《佛密诸事》第二十一章:梦诏
- 梦里人第二十一章
- 第二章第二十一题
- 第三章第二十一题
- 第二章 第二十一题
- 第三章第二十一题
- 第三章第二十一题
- QT 中如何正确使用QThread
- Joda Time获取零点、月初、月末时间
- 关于asp的select case无效的问题!
- 二维码名片
- OpenCV根据矩形轮廓进行倾斜校正
- 第二十一章:并发(下)
- JavaMail使用SMTP协议发送电子邮件(详解)
- 数据库事务的四个基本特征以及事务的隔离级别
- Leetcode#27. Remove Element
- CSMA/CD和CSMA/CA详解
- mybatis中的mapper接口文件以及example类的实例函数以及详解 转载 2016年03月18日 10:28:46 19170213 [java] view plain copy ##Exa
- LeetCode 28. Implement strStr()
- 已解决:undefined symbol: PyFPE_jbuf
- Android导入Volley包