* 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. Потърсете грешки и предложете оптимизации в този и в предишните примери.
Добави коментар