Мы создадим пул объектов Fat, чтобы свести к минимуму затраты на выполнение конструктора. Для тестирования класса Pool будет создана задача, которая забирает объекты Fat для использования, удерживает их в течение некоторого времени, а затем возвращает обратно:
// concurrency/SemaphoreDemo java // Тестирование класса Pool import java.util.concurrent.*; import java util *;
import static net.mindview.util.Print.*;
// Задача для получения ресурса из пула: class CheckoutTask
}
public void run() { try {
T item = pool.checkoutО;
print(this + "checked out " + item); продолжение &
TimeUnit SECONDS sleep(l), pri nt(thi s +"checking in " + item), pool checkln(item). } catch(InterruptedException e) {
// Приемлемый способ завершения
}
}
public String toStringO {
return "CheckoutTask " + id + " ";
public class SemaphoreDemo {
final static int SIZE = 25;
public static void main(String[] args) throws Exception { final Pool
new Pool
exec.execute(new CheckoutTask
}
Future> blocked = exec submit(new RunnableO { public void runO { try {
// Семафор предотвращает лишний вызов checkout. // поэтому следующий вызов блокируется: pool checkOutO. } catch(InterruptedException e) {
pri nt("checkout() Interrupted");
}
}
}):
TimeUnit.SECONDS sleep(2);
blocked.cancel(true); // Выход из заблокированного вызова print("Checking in objects in " + list); for(Fat f • list)
pool checkln(f); for(Fat f : list)
pool.checkln(f); // Второй вызов checkln игнорируется exec.shutdown О;
}
} ///:-
В коде main() создается объект Pool для хранения объектов Fat, после чего группа задач CheckoutTask начинает использовать Pool. Далее поток main() начинает выдавать объекты Fat, не возвращая их обратно. После того как все объекты пула будут выданы, семафор запрещает дальнейшие выдачи. Метод run() блокируется, и через две секунды вызывается метод cancel(). Лишние возвраты Pool игнорирует.
Exchanger
Класс Exchanger представляет собой «барьер», который меняет местами объекты двух задач. На подходе к барьеру задачи имеют один объект, а на выходе — объект, ранее удерживавшийся другой задачей. Объекты Exchanger обычно используются в тех ситуациях, когда одна задача создает высокозатратные объекты, а другая задача эти объекты потребляет.
Чтобы опробовать на практике класс Exchanger, мы создадим задачу-постав-щика и задачу-потребителя, которые благодаря параметризации и генераторам могут работать с объектами любого типа. Затем эти параметризованные задачи будут применены к классу Fat. ExchangerProducer и ExchangerConsumer меняют местами List