}
public void run О {
try {
sleep(duration), } catchdnterruptedException e) {
print(getName() + " прерван " +
"isInterruptedO• " + islnterrupted()),
return;
}
print(getName() + " активизировался"),
}
}
class Joiner extends Thread { private Sleeper sleeper, public Joiner(String name. Sleeper sleeper) { super(name), this.sleeper = sleeper. startO;
}
public void runO { try {
sleeper joinO; } catchdnterruptedException e) { print("Прерван");
}
print (getNameO + " join завершен");
public class Joining {
public static void main(String[] args) { Sleeper
sleepy = new Sleeper("Sleepy". 1500), grumpy = new SIeeper("Grumpy". 1500).
Joiner
dopey = new Joiner("Dopey", sleepy), doc = new Joiner("Doc", grumpy); grumpy interruptO;
}
} /* Output-
Grumpy был прерван. isInterruptedO. false Doc join завершен Sleepy активизировался Dopey join завершен *///;-
Класс Sleeper — это тип потока, который приостанавливается на время, указанное в его конструкторе. В методе run() вызов метода sleep() может закончиться по истечении времени задержки, но может и прерваться. В секции catch выводится сообщение о прерывании, вместе со значением, возвращаемым методом islnterrupted(). Когда другой поток вызывает interrupt() для данного потока, устанавливается флаг, показывающий, что поток был прерван. Однако этот флаг сбрасывается при обработке исключения, поэтому внутри секции catch результатом всегда будет false. Флаг используется в других ситуациях, где поток может исследовать свое прерванное состояние в стороне от исключения.
Joiner — поток, который ожидает пробуждения потока Sleeper, вызывая для последнего метод join(). В методе main() каждому объекту Joiner сопоставляется Sleeper, и вы можете видеть в результатах работы программы, что, если Sleeper был прерван или завершился нормально, Joiner прекращает работу вместе с потоком Sleeper.
Совместное использование ресурсов
Однопоточную программу можно представить в виде одинокого работника, передвигающегося по своему пространству задачи и выполняющего по одной операции за один раз. Раз работник один, вам не приходится принимать во внимание проблему двух сущностей, пытающихся оспорить право на один и тот же ресурс, подобно двум людям, которые хотят одновременно поставить машину в одном месте, вдвоем пройти в одну дверь или даже говорить одновременно.
В условиях многозадачности ситуация меняется: у вас есть сразу два или три потока, которые стремятся получить доступ к одному и тому же ограниченному ресурсу. Если не предотвратить подобные конфликты, два потока могут попытаться получить доступ к одному счету в банке, одновременно распечатать два документа на одном принтере, изменить одно и то же значение, и т. п.
Некорректный доступ к ресурсам
Рассмотрим следующий пример, в котором одна задача генерирует четные числа, а другие задачи эти числа потребляют. Единственной задачей задач-потребите-лей является проверка четности этих чисел.
Начнем с определения EvenChecker, задачи-потребителя, поскольку она будет использоваться во всех последующих примерах. Чтобы отделить EvenChecker от различных генераторов, с которыми мы будем экспериментировать, мы определим абстрактный класс IntGenerator, содержащий минимум необходимых методов для EvenChecker: метод для получения следующего значения next() и методы отмены. Класс не реализует интерфейс Generator, потому что он должен выдавать int, а параметризация не поддерживает примитивные параметры.