Философия Java3
Шрифт:
}
} /* Output:
Итоговое значение: Fat id: 29999 *///.-
В методе main для обеих задач создается один объект Exchanger, а для перестановки создаются два контейнера CopyOnWriteArrayList. Эта разновидность List нормально переносит вызов метода remove при перемещении по списку, не выдавая исключения ConcurrentModificationException. ExchangerProducer заполняет список, а затем меняет местами заполненный список с пустым, передаваемым от ExchangerConsumer. Благодаря Exchanger заполнение списка происходит одновременно с использованием уже заполненного списка.
Моделирование
Одна
whi 1е(!Thread interruptedO) {
holder = exchanger.exchange(holder), for(T x . holder) {
value = x; // Выборка значения holder remove(x); // Нормально для
CopyOnWri teArrayLi st
Примеры HorseRace.java и GreenhouseScheduler.java, приведенные ранее, тоже можно считать своего рода имитаторами.
Модель кассира
В этой классической модели объекты появляются случайным образом и обслуживаются за случайное время ограниченным количеством серверов. Моделирование позволяет определить идеальное количество серверов. Продолжительность обслуживания в следующей модели зависит от клиента и определяется случайным образом. Вдобавок мы не знаем, сколько новых клиентов будет прибывать за каждый период времени, поэтому эта величина тоже определяется случайным образом.
//. concurrency/BankTel1erSimulation.java
// Пример использования очередей и многопоточного программирования. // {Args. 5}
import java.util.concurrent *. import java.util *;
// Объекты, доступные только для чтения, не требуют синхронизации-class Customer {
private final int serviceTime, public Customer(int tm) { serviceTime = tm; } public int getServiceTimeO { return serviceTime; } public String toStringO {
return "[" + serviceTime + "]";
}
}
// Очередь клиентов умеет выводить информацию о своем состоянии: class CustomerLine extends ArrayBlockingQueue<Customer> { public Customerl_ine(int maxLineSize) { super(maxLineSize),
}
public String toStringO {
ifCthis sizeO == 0)
return "[Пусто]"; StringBuilder result = new StringBuilderO; for(Customer customer this)
result append(customer), return result toStringO,
}
}
// Случайное добавление клиентов в очередь: class CustomerGenerator implements Runnable { private CustomerLine customers, private static Random rand = new Random(47), public CustomerGenerator(CustomerLine cq) { customers = cq,
}
public void runO { try {
while(IThread.interruptedO) {
TimeUnit MILLISECONDS.sleep(rand nextlnt(300)):
продолжение &
customers put(new Customer(rand nextlnt(lOOO)));
}
} catchdnterruptedException e) {
System.out.pri ntin("CustomerGenerator i nterrupted");
}
System.out printin("CustomerGenerator terminating");
class Teller implements Runnable. Comparable<Teller> { private static int counter = 0; private final int id = counter**; //
Счетчик клиентов, обслуженных за текущую смену: private int customersServed = 0; private CustomerLine customers; private boolean servingCustomerLine = true; public Teller(CustomerLine cq) { customers = cq; } public void run О { try {while(IThread.interruptedO) {
Customer customer = customers.takeO. Ti meUni t.MILLISECONDS.s1eep(
customer. getServiceTimeO); synchronized(this) {
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<Teller> workingTellers =
new PriorityQueue<Teller>; private Queue<Teller> tellersDoingOtherThings =
new LinkedList<Tel 1 er>; private int adjustmentPeriod. private static Random rand = new Random(47); public TellerManager(ExecutorService e,
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)