Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

Начнем с определения EvenChecker, задачи-потребителя, поскольку она будет использоваться во всех последующих примерах. Чтобы отделить EvenChecker от различных генераторов, с которыми мы будем экспериментировать, мы определим абстрактный класс IntGenerator, содержащий минимум необходимых методов для EvenChecker: метод для получения следующего значения next и методы отмены. Класс не реализует интерфейс Generator, потому что он должен выдавать int, а параметризация не поддерживает примитивные параметры.

//: concurrency/IntGenerator.java

public abstract class IntGenerator {

private volatile boolean canceled = false; public abstract int nextO; // Для отмены:

public void cancel О { canceled = true; } public boolean isCanceledO { return canceled; }

} III ~

IntGenerator содержит метод cancel, изменяющий состояние флага canceled, и метод isCanceled, проверяющий, был ли объект отменен. Поскольку флаг canceled относится к типу boolean, простые операции вроде присваивания и возврата значения выполняются атомарно, то есть без возможности прерывания, и вы не увидите поле в промежуточном состоянии между этими простыми операциями. Смысл ключевого слова volatile будет объяснен позже в этой главе.

Для тестирования IntGenerator можно воспользоваться следующим классом EvenChecker:

//. concurrency/EvenChecker.java import java.util.concurrent *,

public class EvenChecker implements Runnable { private IntGenerator generator, private final int id,

public EvenChecker(IntGenerator g. int ident) { generator = g. id = ident;

}

public void run О {

while({generator isCanceledO) {

int val = generator.nextO; if(val % 2 \= 0) {

System.out.println(val + " не четно!"); generator cancel О; // Отмена всех EvenChecker

}

// Тестирование произвольного типа IntGenerator-public static void test(IntGenerator gp. int count) {

System out.println("Ha>KMme Control-С. чтобы завершить программу"), ExecutorService exec = Executors.newCachedThreadPoolО; for(int i = 0; i < count; i++)

exec.execute(new EvenChecker(gp, i)); exec.shutdownO;

}

// Значение по умолчанию для count: public static void test(IntGenerator gp) { test(gp. 10);

}

} ///-

Как видно из run, все задачи EvenChecker, зависящие от объекта IntGenerator, проверяют, не были ли они отменены. При таком подходе задачи, совместно использующие общий ресурс (IntGenerator), наблюдают за ресурсом, ожидая от него сигнала завершения. Тем самым устраняется так называемая «ситуация гонки», когда две и более задачи торопятся отреагировать на некоторое условие; это приводит к возникновению конфликтов или получению других некорректных результатов. Будьте внимательны, постарайтесь продумать все возможные сбои в системах с параллельным выполнением и защититься от них. Например, задача не может зависеть от другой задачи, потому что порядок завершения задач не гарантирован. Зависимость задач от объекта, не являющегося задачей, устраняет потенциальную «ситуацию гонки».

Метод test настраивает и тестирует произвольный тип IntGenerator, запуская несколько задач EvenChecker с общим IntGenerator. Если IntGenerator приводит к сбою, test сообщает о происходящем и возвращает управление. В противном случае его следует завершить вручную клавишами Ctrl+C.

Задачи EvenChecker постоянно читают и проверяют значения, полученные от IntGenerator. Если generator.isCanceled равен true, run возвращает управление; это сообщает Executor в EvenChecker.test о том, что задача завершена. Любая задача EvenChecker может вызвать cancel для связанного с ней IntGenerator, в результате чего все остальные EvenChecker, использующие IntGenerator, будут корректно завершены. Как будет показано далее в этой главе, в Java существуют и более общие механизмы завершения потоков.

В первом варианте IntGenerator, который мы рассмотрим, next выдает серию четных значений:

// concurrency/EvenGenerator java

// Конфликт потоков

public class EvenGenerator extends IntGenerator { private int currentEvenValue = 0, public int nextO {

++currentEvenValue. // Опасная точка!

++currentEvenValue;

return currentEvenValue,

}

public static void main(String[] args) {

EvenChecker test(new EvenGenerator),

}

} /* Output

Нажмите Control-С, чтобы завершить программу

89476993 не четно!

89476993 не четно!

*/// ~

Одна задача может вызвать next после того, как другая задача выполнит первый инкремент currentEvenValue, но до второго инкремента (в позиции, помеченной комментарием «Опасная точка!»). При этом значение оказывается в «некорректном» состоянии. Чтобы доказать, что такое возможно, EvenChecker. test создает группу объектов EvenChecker, которые непрерывно читают результаты EvenGenerator и проверяют их на четность. При обнаружении нечетного числа выводится сообщение об ошибке, и программа завершается.

Сбой рано или поздно произойдет, потому что задачи EvenChecker могут обратиться к информации EvenGenerator в «некорректном» состоянии. Впрочем, проблема может проявиться лишь после многих циклов отработки EvenGenerator; все зависит от особенностей операционной системы и других подробностей реализации. Чтобы ускорить наступление сбоя, попробуйте разместить вызов yield между инкрементами. В этом и состоит одна из проблем многопоточного программирования: программа, содержащая ошибку, на первый взгляд работает вполне нормально — а все потому, что вероятность сбоя очень мала.

Также стоит учитывать, что сама операция инкремента состоит из нескольких шагов и может быть прервана планировщиком потоков в ходе выполнения — другими словами, инкремент в Java не является атомарной операцией. Даже простое приращение переменной может оказаться небезопасным, если не организовать защиту задачи.

Разрешение конфликтов доступа

Предыдущий пример показательно иллюстрирует основную проблему потоков: вы никогда не знаете, когда поток будет выполняться. Вообразите, что вы сидите за столом с вилкой в руках, собираетесь съесть последний, самый лакомый кусочек, который лежит на тарелке прямо перед вами. Но, как только вы тянетесь к еде вилкой, она исчезает (как ваш поток был внезапно приостановлен, и другой поток не постеснялся «стянуть» у вас еду). Вот такую проблему нам приходится решать при написании выполняемых одновременно и использующих общие ресурсы программ. Чтобы многопоточность работала, необходим механизм, предотвращающий возможность состязания двух потоков за один ресурс (по крайней мере, во время критичных операций).

Поделиться:
Популярные книги

Третий. Том 5

INDIGO
5. Отпуск
Фантастика:
космическая фантастика
фантастика: прочее
5.00
рейтинг книги
Третий. Том 5

Содержанка. Книга 2

Вечная Ольга
6. Порочная власть
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Содержанка. Книга 2

Цикл "Идеальный мир для Лекаря". Компиляция. Книги 1-30

Сапфир Олег
Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Цикл Идеальный мир для Лекаря. Компиляция. Книги 1-30

Хроники Тириса. Книга 3

Маханенко Василий Михайлович
3. Хроники Тириса
Фантастика:
боевая фантастика
космическая фантастика
фантастика: прочее
5.00
рейтинг книги
Хроники Тириса. Книга 3

Макаров

Семанов Сергей Николаевич
515. Жизнь замечательных людей
Документальная литература:
биографии и мемуары
8.33
рейтинг книги
Макаров

Метатель. Книга 2

Тарасов Ник
2. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель. Книга 2

Золотой ворон

Сакавич Нора
5. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Золотой ворон

Двойник Короля 7

Скабер Артемий
7. Двойник Короля
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Двойник Короля 7

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Отмороженный 12.0

Гарцевич Евгений Александрович
12. Отмороженный
Фантастика:
боевая фантастика
попаданцы
рпг
фантастика: прочее
5.00
рейтинг книги
Отмороженный 12.0

Законы Рода. Том 7

Мельник Андрей
7. Граф Берестьев
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Законы Рода. Том 7

Жена неверного маршала, или Пиццерия попаданки

Удалова Юлия
Любовные романы:
любовно-фантастические романы
4.25
рейтинг книги
Жена неверного маршала, или Пиццерия попаданки

Мастер 10

Чащин Валерий
10. Мастер
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 10

Сапер

Вязовский Алексей
1. Сапер
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.29
рейтинг книги
Сапер