customersServed++; while(IservingCustomerLine) waitO;
}
}
} catchdnterruptedException e) {
System out println(this + "прерван");
}
System out.println(this + "завершается");
}
public synchronized void doSomethingElseO { customersServed = 0; servingCustomerLine = false;
}
public synchronized void serveCustomerLineO {
assert IservingCustomerLine:"уже обслуживает: " + this; servingCustomerLine = true; notifyAl 10;
}
public String toStringO { return "Кассир " + id + " "; } public String shortStringO { return "K" + id. } // Используется приоритетной очередью: public synchronized int compareTo(Teller other) {
return customersServed < other customersServed ? -1 .
(customersServed == other.customersServed ? 0 . 1);
}
}
class TellerManager implements Runnable { private ExecutorService exec, private CustomerLine customers; private PriorityQueue
new PriorityQueue
new LinkedList
CustomerLine customers, int adjustmentPeriod) { exec = e;
this.customers = customers;
this.adjustmentPeriod = adjustmentPeriod;
// Начинаем с одного кассира:
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
}
public void adjustTellerNumberO {
// Фактически это система управления. Регулировка числовых // параметров позволяет выявить проблемы стабильности // в механизме управления.
// Если очередь слишком длинна, добавить другого кассира: if(customers.size() / workingTellers.sizeO > 2) { // Если кассиры отдыхают или заняты // другими делами, вернуть одного из них: if(tellersDoingOtherThings.size() > 0) {
Teller teller = tellersDoingOtherThings.remove(); tel1er.serveCustomerLi ne(); workingTellers.offer(teller); return;
}
// Иначе создаем (нанимаем) нового кассира Teller teller = new Teller(customers); exec.execute(teller); workingTellers.add(teller); return;
}
// Если очередь достаточно коротка, освободить кассира: if (workingTellers.sizeO > 1 &&
customers.size() / workingTellers.sizeO < 2) reassignOneTellerO; // Если очереди нет. достаточно одного кассира: if (customers, si ze() ==0)
while(workingTellers.size() > 1) reassignOneTellerO;
}
// Поручаем кассиру другую работу или отправляем его отдыхать: private void reassignOneTellerO {
Teller teller = workingTellers.pollО;
tel 1 er. doSomethi ngEl seO,
tel1ersDoi ngOtherThi ngs.offer(tel1er);
}
public void runO { try {
while(!Thread.interruptedO) {
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
adjustTellerNumberO;
System.out.print(customers +"{");
for(Teller teller ■ workingTellers)
System.out.print(teller.shortString() + " "); System.out.printIn("}");
} catchdnterruptedException е) {
System.out.printin(this + "прерван");
}
System.out println(this + "завершается");
}
public String toStringO { return "TellerManager "; }
}
public class BankTellerSimulation {
static final int MAX_LINE_SIZE = 50;
static final int ADJUSTMENT_PERIOD = 1000;
public static void main(String[] args) throws exception {
ExecutorService exec = Executors.newCachedThreadPoolО; // Если очередь слишком длинна, клиенты уходят: CustomerLine customers =
new CustomerLi ne(MAX_LINE_SIZE); exec.execute(new CustomerGenerator(customers)); // TellerManager добавляет и убирает кассиров // по мере необходимости: exec.execute(new TellerManager(
exec, customers. ADJUSTMENT_PERIOD)); if(args.length > 0) // Необязательный аргумент
Ti meUni t.SECONDS.s1eep(new Integer(args[0])).
else {
System.out.printIn("Press 'Enter' to quit"); System.in.readО;
}
exec.shutdownNowO;
}
} /* Output:
[429][200][207] { K0 K1 } [861][258][140][322] { K0 K1 } [575][342][804][826][896][984] { КО K1 K2 } [984][810][141][12][689][992][976][368][395][354] { КО K1 K2 КЗ } Teller 2 прерван Teller 2 завершается Teller 1 прерван Teller 1 завершается TellerManager прерван TellerManager завершается Teller 3 прерван Teller 3 завершаетсяч Teller 0 прерван Teller 0 завершается CustomerGenerator прерван CustomerGenerator завершается *///:-
Объекты Customer очень просты; они содержат только поле данных final int. Так как эти объекты никогда не изменяют своего состояния, они являются
Класс CustomerLine представляет собой общую очередь, в которой клиенты ожидают обслуживания. Он реализован в виде очереди ArrayBlockingQueue с методом toString(), который выводит результаты в желаемом формате.
Генератор CustomerGenerator присоединяется к CustomerLine и ставит объекты Customer в очередь со случайными интервалами.