}
class WaxOff implements Runnable { private Car car;
public WaxOff(Car c) { car = c; } public void runO { try {
while(IThread.interruptedO) { car.waitForWaxingO; printnbC'Wax Off! "); Ti mellni t. MILLI SECONDS. s 1 eep (200); car.buffedO;
}
} catchdnterruptedException e) {
printC'Exiting via interrupt");
}
printC'Ending Wax Off task");
public class WaxOMatic {
public static void main(String[] args) throws Exception { Car car = new CarO;
ExecutorService exec = Executors.newCachedThreadPoolО;
exec.execute(new WaxOff(car));
exec.execute(new WaxOn(car));
TimeUnit SECONDS.sieep(5); // Небольшая задержка. .
exec.shutdownNowO; // Прерывание всех задач
}
} /* Output:
Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Wax Off! Wax On! Exiting via interrupt Ending Wax On task Exiting via interrupt Ending Wax Off task *///:-
Класс Саг содержит одну логическую переменную waxOn, которая описывает текущее состояние процесса полировки.
Метод waitForWaxing() проверяет флаг waxOn, и, если он равен false, вызывающая задача приостанавливается вызовом wait(). Очень важно, что это происходит в синхронизированном методе. При вызове wait() поток приостанавливается, а блокировка снимается. Последнее принципиально, потому что для безопасного изменения состояния объекта (например, для присваивания waxOn значения true, без чего приостановленная задача не сможет продолжить работу) блокировка должна быть доступна для другой задачи. В нашем примере при вызове другой задачей метода waxed(), указывающего, что пришло время что-то сделать, для задания истинного значения waxOn необходимо установить блокировку. Затем waxed() вызывает notifyAll(); задача, приостановленная вызовом wait(), активизируется. Для этого нужно сначала заново получить блокировку, освобожденную при входе в wait(). Задача не активизируется, пока блокировка не станет доступной.
Использование каналов для ввода/вывода между потоками
Часто бывает полезно организовать взаимодействие потоков посредством механизмов ввода/вывода. Библиотеки потоков могут предоставлять поддержку ввода/вывода между потоками в форме каналов (pipes). Последние представлены в стандартной библиотеке ввода/вывода Java классами PipedWriter (позволяет потоку записывать в канал) и PipedReader (предоставляет возможность другому потоку считывать из того же канала).
Простой пример взаимодействия двух потоков через канал:
//• concurrency/PipedlO.java
// Использование каналов для ввода/вывода между потоками
import java.util.concurrent.*;
import java.io.*;
import java.util.*;
import static net.mindview.util.Print.*;
class Sender implements Runnable {
private Random rand = new Random(47); private PipedWriter out = new PipedWriterO; pubTic PipedWriter getPipedWriterO { return out, } public void run() { try {
while(true)
for(char с = 'А'; с <= 'z'; С++) { out write(c);
TimeUnit.MILLISECONDS.sleep(rand.nextlnt(500));
}
} catch(IOException e) {
print(e + " Sender write exception"); } catch(InterruptedException e) {