* Consumer-Producer – двустранна синхронизация с много консуматори и много производители
Публикувано на 29 ноември 2013 в раздел ПИК3 Java.
В предишните примери се забеляза нещо много неприятно - кодът се обърква все повече и повече. Причината за това е, че при множество играчи, не само производителя трябва да уведомява консуматора и обратно, а и самите консуматори и самите производители трябва да се синхронизират помежду си. Поради тази причина ще е по-добре ако оптимизираме идеята за централно синхронизиране на всички чрез "чинията".
В този пример има споделен ресурс – чиния с храна. За нея има ограничение какво количество храна ще поеме - максимум 10 единици (по този начин усложняваме задачата, защото хората трябва да се изчакват!). Кучетата ще нападат чинията в произволен ред. Ако в нея няма храна, кучето се отдръпва, за да даде възможност на човек да добави храна (има continue в цикъла на run метода). Същото вършат и хората - те сготвят храната и гледат купичката. Ако тя е пълна, те се отдръпват и чакат. Поддържат се броячи за броя на активните кучета и активните готвачи. Ако готвачите станат повече от кучетата, някой от готвачите ще спира работата си.
public class CP{ static Dog[] dogs = new Dog[4]; static Human[] humans = new Human[3]; static Dish dish = new Dish(dogs.length, humans.length); public static void main(String[] args){ System.out.println("Program running"); dogs[0] = new Dog("Sharo 1"); dogs[1] = new Dog("Sharo 2"); dogs[2] = new Dog("Sharo 3"); dogs[3] = new Dog("Sharo 4"); humans[0] = new Human("Ivan1"); humans[1] = new Human("Ivan2"); humans[2] = new Human("Ivan3"); dogs[0].start(); dogs[1].start(); humans[0].start(); humans[1].start(); dogs[2].start(); dogs[3].start(); humans[2].start(); } } class Dish{ volatile int activeDogsCount; volatile int activeCookersCount; volatile int amount; public Dish(int dogs, int humans){ this.amount = 0; activeDogsCount = dogs; activeCookersCount = humans; } synchronized void add(int amount){ this.amount += amount; this.notifyAll(); } synchronized int get(){ int result = this.amount; this.amount = 0; this.notifyAll(); return result; } } class Dog extends Thread{ int stomach; String name; public Dog(String name){ this.name = name; this.stomach = 0; } public void run(){ try{ while(this.stomach < 100){ synchronized(CP.dish){ if(CP.dish.amount==0){ CP.dish.wait(); continue; } this.getFood(); } } } catch(InterruptedException e){ System.out.println(this.name+" will not feed full"); } System.out.println(this.name+" woof!"); CP.dish.activeDogsCount--; } void getFood() throws InterruptedException{ int ate = CP.dish.get(); this.stomach += ate; this.sleep((int)(Math.random()*500)); // eating System.out.println(this.name+" burp! Ate = "+ate+", stomach = "+this.stomach); } } class Human extends Thread{ String name; boolean haveFoodInHands; public Human(String name){ this.name = name; this.haveFoodInHands = false; } public void run(){ try{ while(CP.dish.activeDogsCount >= CP.dish.activeCookersCount){ if(!this.haveFoodInHands) this.cook(); synchronized(CP.dish){ if(CP.dish.amount>0){ CP.dish.wait(); continue; } CP.dish.add(10); this.haveFoodInHands = false; System.out.println(this.name+" added food to dish! Dish amount = "+CP.dish.amount); } } } catch(InterruptedException e){ System.out.println(this.name+" will stop cooking"); } finally{ System.out.println(this.name+" stopped cooking!"); CP.dish.activeCookersCount--; } } void cook() throws InterruptedException{ this.sleep((int)(Math.random()*500)); System.out.println(this.name+" food ready..."); } }
Задача 1. Почистете кода и го направете по-пригледен.
Задача 2. Потърсете грешки и предложете оптимизации в този и в предишните примери.
Добави коментар