class ExchangerConsumer> exchanger; private List
ExchangerConsumer(Exchanger> ex, List
}
public void runO {
} catch(InterruptedException e) {
// Приемлемый способ завершения
}
System out.printlnC'HToroBoe значение- " + value).
}
}
public class ExchangerDemo { static int size = 10; static int delay = 5; // Секунды
public static void main(String[] args) throws Exception { if(args.length > 0)
size = new lnteger(args[0]), if(args.length > 1)
delay = new Integer(args[l]); ExecutorService exec = Executors.newCachedThreadPoolО. Exchanger> xc = new Exchanger
producerList = new CopyOnWriteArrayList
BasicGenerator.create(Fat.class). producerList)); exec.execute(
new ExchangerConsumer
}
} /* 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
}
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
while(IThread.interruptedO) {
Customer customer = customers.takeO. Ti meUni t.MILLISECONDS.s1eep(
customer. getServiceTimeO); synchronized(this) {