При участии Тима Перлса, Джошуа Блоха, Джозева Боубира, Дэвида Холмса и Дага Ли Параллельное программирование в java на
Скачать 4.97 Mb.
|
Брайан Гоетс при участии Тима Перлса, Джошуа Блоха, Джозева Боубира, Дэвида Холмса и Дага Ли Параллельное программирование в JAVA на практике Перевод: Сорокин А.В. О книге Java Concurrency на практике Мне посчастливилось работать с фантастической командой над дизайном и реализацией функций параллелизма, добавленных к платформе Java в Java 5.0 и Java 6. Теперь эта же команда даёт лучшее объяснение этих новых функций и параллелизма в целом. Параллелизм больше не является темой только для опытных пользователей. Каждый Разработчик Java должен прочитать эту книгу. —Martin Buchholz JDK Concurrency Czar, Sun Microsystems В течении прошедших 30 лет рост производительности компьютеров обусловливался законом Мура; отныне он будет зависеть от закона Амдала. Написание кода, эффективно использующего несколько процессоров, может быть очень сложным. Книга Java Concurrency in Practice знакомит вас с концепциями и техниками, необходимыми для написания безопасных и масштабируемых Java- программ для сегодняшних - и завтрашних - систем. —Doron Rajwan Research Scientist, Intel Corp Эта книга вам необходима, если вы пишите – или разрабатываете, или отлаживаете, или развёртываете, или обдумываете – многопоточные Java- программы. Если вам когда-либо приходилось «синхронизировать» метод, и вы небыли уверены в том, для чего это делаете, вы задолжали самому себе и вашим пользователям обязанность прочитать эту книгу, от корки до корки. —Ted Neward Author of Effective Enterprise Java Брайан рассматривает фундаментальные проблемы и сложности параллелизма с необычайной ясностью. Эту книгу должен прочесть каждый из тех, кто использует потоки и заботится и производительности. —Kirk Pepperdine CTO, JavaPerformanceTuning.com Эта книга охватывает очень глубокую и тонкую тему в очень ясной и краткой манере, что делает её превосходным справочным руководством по параллелизму Java. Каждая страница заполнена проблемами (и решениями!) с которыми программисты борются каждый день. Эффективное использование параллелизма становится все более и более важным, ведь теперь Закон Мура, предоставляет большее количество ядер, но они не становятся быстрее, и эта книга покажет вам, как это сделать. —Dr. Cliff Click Senior Software Engineer, Azul Systems Я очень сильно интересуюсь параллелизмом, и, вероятно, написал большее количество взаимоблокировок потоков и допустил большее количество ошибок синхронизации, чем большинство других программистов. Книга Брайана наиболее читаема по теме параллельности и многопоточности в Java, и имеет дело с этой сложной темой с прекрасным практическим подходом. Это книга, которую я рекомендую всем моим читателям в The Java Specialists’ Newsletter, потому что она интересна, полезна и релевантна к проблемам, с которыми разработчики Java сталкиваются лицом к лицу каждый день. —Dr. Heinz Kabutz The Java Specialists’ Newsletter Я сосредоточил свою карьеру на упрощении простых проблем, но эта книга честолюбиво и эффективно работает над упрощением сложной, но важной темы: параллелизма. Книга Java Concurrency in Practice является революционной в своем подходе, гладкой и с легким стилем, и очень своевременной в появлении — ей суждено стать очень важной книгой. —Bruce Tate Author of Beyond Java Java Concurrency in Practice является неоценимой компиляцией ноу-хау о потоках для разработчиков Java. Я обнаружил, что чтение этой книги интеллектуально захватывающе, отчасти потому, что это превосходное введение в API параллелизма Java, но в основном потому, что она полностью и доступно охватывает экспертные знания в области потоков, которые нелегко найти в другом месте. —Bill Venners Author of Inside the Java Virtual Machine Параллельное программирование в Java на практике Java Concurrency in Practice Brian Goetz with Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes and Doug Lea Upper Saddle River, NJ • Boston • Indianapolis • San Francisco New York • Toronto • Montreal • London • Munich • Paris • Madrid Capetown • Sydney • Tokyo • Singapore • Mexico City Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trade-marks. Where those designations appear in this book, and the publisher was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals. The authors and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein. The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which may include electronic versions and/or custom covers and content particular to your business, training goals, marketing focus, and branding interests. For more information, please contact: U.S. Corporate and Government Sales (800) 382-3419 corpsales@pearsontec hgroup.com For sales outside the United States, please contact: International Sales international@pearsoned.com Visit us on the Web: www.awprofessional.com This Book Is Safari Enabled The Safari® Enabled icon on the cover of your favorite technology book means the book is available through Safari Bookshelf. When you buy this book, you get free access to the online edition for 45 days. Safari Bookshelf is an electronic reference library that lets you easily search thousands of technical books, find code samples, download chapters, and access technical information whenever and wherever you need it. To gain 45-day Safari Enabled access to this book: • Go to http://www.awprofessional.com/safarienabled • Complete the brief registration form • Enter the coupon code UUIR-XRJG-JWWF-AHGM-137Z If you have difficulty registering on Safari Bookshelf or accessing the online edition, please e-mail customer-ser-vice@safaribooksonline.com. Library of Congress Cataloging-in-Publication Data Goetz, Brian. Java Concurrency in Practice / Brian Goetz, with Tim Peierls. . . [et al.] p. cm. Includes bibliographical references and index. ISBN 0-321-34960-1 (pbk. : alk. paper) 1. Java (Computer program language) 2. Parallel programming (Computer science) 3. Threads (Computer programs) I. Title. QA76.73.J38G588 2006 005.13'3--dc22 2006012205 Copyright © 2006 Pearson Education, Inc. ISBN 0-321-34960-1 Джессике От переводчика Как родился этот перевод? Да, в общем-то, достаточно просто. Всегда хотелось прочитать эту книгу на русском языке, но годы шли, а издательства книгу всё не переводили. В какой-то момент появилось понимание, что книгу переводить не будут, т.к. она «устарела», ей уже 13 лет. И постепенно стала зреть мысль, что можно её перевести самому. Вот так и вызрел план перевода. Когда я только планировал перевод, всё казалось легко и просто, думал, кавалерийским наскоком, быстренько, за месяц всё сделаю. А потом началась работа над переводом, и бросать это дело было уже поздно. Перевод – довольно сложный процесс. Приходится держать в голове множество понятий. Множество раз приходилось пробегаться по тексту книги, когда подбирал более удачный перевод для какого- либо термина. От этого в переводе могут быть небольшие несогласованности и опечатки. Но, несмотря на сложность, было очень интересно. Переведя эту книгу практически от корки до корки (не считая какой-то мишуры от издательства) могу сказать, что это фундаментальный труд, и он ни сколько не устарел. Считаю, что перевод этой книги является ценным вкладом в копилку знаний сообщества Java- разработчиков. Может быть, кто-то последует моему примеру, и также возьмётся перевести те книги, которые уже никогда не увидят свет на русском языке по коммерческим соображениям. Репозиторий с проектом перевода книги: git@github.com:Lulay82/JavaConcurrencyInPracticeTranslation.git Сорокин А.В. Екатеринбург, июнь 2018 - декабрь 2018. Оглавление От переводчика ................................................................................................................. 8 Оглавление ........................................................................................................................ 9 Предисловие .................................................................................................................... 15 Как читать эту книгу ...................................................................................................... 16 Примеры кода ................................................................................................................. 18 Часть I Основы ................................................................................................................ 19 Глава 1 Введение ............................................................................................................ 20 1.1 Очень краткая история параллелизма ................................................................. 20 1.2 Преимущества потоков ........................................................................................ 22 1.2.1 Использование нескольких процессоров ..................................................... 22 1.2.2 Упрощение моделирования .......................................................................... 22 1.2.3 Упрощённая обработка асинхронных событий .......................................... 23 1.2.4 Более отзывчивый пользовательский интерфейс ....................................... 24 1.3 Риски, которые несут потоки ............................................................................... 24 1.3.1 Угрозы безопасности ..................................................................................... 25 1.3.2 Угрозы живучести потока ............................................................................. 27 1.3.3 Угрозы производительности ......................................................................... 28 1.4 Потоки есть везде ................................................................................................. 28 Глава 2 Потокобезопасность ......................................................................................... 31 2.1 Что такое потокобезопасность? ........................................................................... 33 2.1.1 Пример: сервлет без сохранения состояния (stateless) ............................... 34 2.2 Атомарность .......................................................................................................... 35 2.2.1 Условия гонок ................................................................................................ 36 2.2.2 Пример: состояние гонки в отложенной инициализации .......................... 37 2.2.3 Составные действия ...................................................................................... 38 2.3 Блокировка ............................................................................................................ 40 2.3.1 Внутренние блокировки ................................................................................ 41 2.3.2 Повторная входимость .................................................................................. 42 2.4 Защита состояния с помощью блокировок ........................................................ 43 2.5 Живучесть и производительность ....................................................................... 46 Глава 3 Совместно используемые объекты .................................................................. 50 3.1 Видимость ............................................................................................................. 50 3.1.1 Устаревшие данные ....................................................................................... 52 3.1.2 Неатомарные 64 битные операции ............................................................... 53 3.1.3 Блокировки и видимость ............................................................................... 53 3.1.4 Volatile переменные ....................................................................................... 54 3.2 Публикация и побег .............................................................................................. 56 3.2.1 Методы безопасного построения ................................................................. 58 3.3 Ограничение потока ............................................................................................. 59 3.3.1 Специальные ограничения потока ............................................................... 60 3.3.2 Ограничение стека ......................................................................................... 60 3.3.3 Класс ThreadLocal .......................................................................................... 62 3.4 Неизменяемость .................................................................................................... 63 3.4.1 Поля типа final ............................................................................................... 65 3.4.2 Использование volatile для публикации неизменяемых объектов ............ 65 3.5 Безопасная публикация ........................................................................................ 66 3.5.1 Некорректная публикация: когда хорошие объекты ведут себя плохо .... 67 3.5.2 Неизменяемые объекты и безопасность инициализации ........................... 68 3.5.3 Идиомы безопасной публикации ................................................................. 69 3.5.4 Фактически неизменяемые объекты ............................................................ 70 3.5.5 Изменяемые объекты .................................................................................... 70 3.5.6 Безопасное совместное использование объектов ....................................... 71 Глава 4 Компоновка объектов ....................................................................................... 72 4.1 Проектирование потокобезопасных классов ..................................................... 72 4.1.1 Сбор требований к синхронизации .............................................................. 73 4.1.2 Операции, зависящие от состояния ............................................................. 74 4.1.3 Владелец состояния ....................................................................................... 74 4.2 Ограничение экземпляра ...................................................................................... 76 4.2.1 Шаблон Java “Монитор” ............................................................................... 78 4.2.2 Пример: отслеживание парка автомобилей................................................. 78 4.3 Делегирование потокобезопасности ................................................................... 81 4.3.1 Пример: транспортный трекер с использованием делегирования ............ 81 4.3.2 Независимые переменные состояния........................................................... 83 4.3.3 Когда делегирование не работает ................................................................ 84 4.3.4 Публикация базовых переменных состояния ............................................. 86 4.3.5 Пример: трекер транспортных средств публикующий своё состояние .... 86 4.4 Добавление функциональности в существующие потокобезопасные классы 88 4.4.1 Блокировка на стороне клиента.................................................................... 89 4.4.2 Композиция .................................................................................................... 91 4.5 Документирование политики синхронизации ............................................... 92 4.5.1 Интерпретация расплывчатой документации ............................................. 93 Глава 5 Строительные блоки ......................................................................................... 95 5.1 Синхронизированные коллекции ........................................................................ 95 5.1.1 Проблемы с синхронизированными коллекциями ..................................... 95 5.1.2 Итераторы и ConcurrentModificationException ............................................ 97 5.1.3 Скрытые итераторы ....................................................................................... 99 5.2 Параллельные коллекции ................................................................................... 100 5.2.1 Класс ConcurrentHashMap ........................................................................... 101 5.2.2 Дополнительные атомарные операции интерфейса Map ......................... 102 5.2.3 Класс CopyOnWriteArrayList ...................................................................... 103 5.3 Блокирующие очереди и шаблон производитель-потребитель ...................... 104 5.3.1 Пример: поиск в компьютере ..................................................................... 106 5.3.2 Последовательное ограничение потока ..................................................... 108 5.3.3 Двусторонние очереди и кража работы ..................................................... 108 5.4 Методы блокирования и прерывания ............................................................... 109 5.5 Синхронизаторы ................................................................................................. 111 5.5.1 Защёлки ........................................................................................................ 111 5.5.2 Класс FutureTask .......................................................................................... 113 5.5.3 Семафоры ..................................................................................................... 115 5.5.4 Барьеры ......................................................................................................... 117 5.6 Создание эффективного и масштабируемого кэша результатов .................... 119 Итоги части I ................................................................................................................. 126 Часть II Структурирование параллельных приложений ........................................... 127 Глава 6 Выполнение задач ........................................................................................... 128 6.1 Выполнение задач в потоках ............................................................................. 128 6.1.1 Последовательное выполнение задач ........................................................ 128 6.1.2 Явное создание потоков для задач ............................................................. 129 6.1.3 Недостатки неограниченного создания потоков ...................................... 130 6.2 Фрэймворк Executor ........................................................................................... 132 6.2.1 Пример: веб-сервер использующий фреймворк Executor ........................ 132 6.2.2 Политики выполнения................................................................................. 134 6.2.3 Пулы потоков ............................................................................................... 134 6.2.4 Жизненный цикл экземпляра Executor ...................................................... 136 6.2.5 Отложенные и периодические задачи ....................................................... 138 6.3 Поиск уязвимостей параллелизма ..................................................................... 139 6.3.1 Пример: последовательный генератор страниц ........................................ 139 6.3.2 Задачи возвращающие результат: Callable и Future ................................. 140 6.3.3 Пример: отрисовка страниц с помощью Future ........................................ 142 6.3.4 Ограничения распараллеливания разнородных задач .............................. 143 6.3.5 CompletionService: Executor пересекается с BlockingQueue .................... 144 6.3.6 Пример: рендер страниц с использованием CompletionService ............... 145 6.3.7 Ограничение времени выполнения задач .................................................. 146 6.3.8 Пример: портал бронирования путешествий ............................................ 147 6.4 Итоги .................................................................................................................... 149 Глава 7 Отмена и завершение ...................................................................................... 150 7.1 Отмена задачи ..................................................................................................... 150 7.1.1 Прерывание .................................................................................................. 152 7.1.2 Политики прерывания ................................................................................. 156 7.1.3 Ответ на прерывание ................................................................................... 157 7.1.4 Пример: запуск по времени ........................................................................ 159 7.1.5 Выполнение отмены с помощью интерфейса Future ................................ 161 7.1.6 Работа с непрерываемыми блокировками ................................................. 162 7.1.7 Инкапсуляция нестандартной отмены с помощью метода newTaskFor . 164 7.2 Остановка служб основанных на потоках ........................................................ 166 7.2.1 Пример: Сервис логирования ..................................................................... 166 7.2.2 Завершение работы ExecutorService .......................................................... 169 7.2.3 Ядовитые пилюли ........................................................................................ 170 7.2.4 Пример: одноразовая служба выполнения ................................................ 172 7.2.5 Ограничения метода shutdownNow ............................................................ 173 7.3 Обработка аварийного завершения потока ...................................................... 175 7.3.1 Обработчики неперехваченных исключений ............................................ 177 7.4 Завершение работы JVM .................................................................................... 178 7.4.1 Завершающие хуки ...................................................................................... 179 7.4.2 Потоки демоны ............................................................................................ 180 7.4.3 Финализаторы .............................................................................................. 181 7.5 Итоги .................................................................................................................... 181 Глава 8 Применение пулов потоков............................................................................ 182 8.1 Неявные связи между задачами и политиками выполнения .......................... 182 8.1.1 Взаимоблокировка потоков, вызванная голоданием ................................ 183 8.1.2 Долговременные задачи .............................................................................. 185 8.2 Размеры пулов потоков ...................................................................................... 185 8.3 Конфигурирование класса ThreadPoolExecutor ............................................... 186 8.3.1 Создание и удаление потока ....................................................................... 187 8.3.2 Управление задачами в очереди ................................................................. 188 8.3.3 Политики насыщения .................................................................................. 190 8.3.4 Фабрики задач .............................................................................................. 192 8.3.5 Настройка экземпляра ThreadPoolExecutor после построения ................ 194 8.4 Расширение класса ThreadPoolExecutor............................................................ 194 8.4.1 Пример: добавление статистики в пул потоков ........................................ 195 8.5 Распараллеливание рекурсивных алгоритмов ................................................. 196 8.5.1 Пример: фрэймворк для решения головоломок ........................................ 198 8.6 Итоги .................................................................................................................... 203 Глава 9 Приложения GUI ............................................................................................. 204 9.1 Почему фреймворки GUI однопоточны? ......................................................... 204 9.1.1 Последовательная обработка событий ...................................................... 206 9.1.2 Ограничение потока в Swing ...................................................................... 206 9.2 Кратковременные задачи GUI ........................................................................... 208 9.3 Долговременные задачи GUI ............................................................................. 210 9.3.1 Отмена .......................................................................................................... 211 9.3.2 Индикатор прогресса и завершения ........................................................... 212 9.3.3 Класс SwingWorker ...................................................................................... 214 9.4 Совместно используемые модели данных ....................................................... 215 9.4.1 Потокобезопасные модели данных ............................................................ 215 9.4.2 Разделение моделей данных ....................................................................... 216 9.5 Другие формы однопоточных подсистем ......................................................... 217 9.6 Итоги .................................................................................................................... 217 Часть 3 III Живучесть, производительность и тестирование ................................... 218 Глава 10 Предотвращение возникновения угроз живучести .................................... 219 10.1 Взаимоблокировки ........................................................................................... 219 10.1.1 Взаимоблокировки, вызванные порядком наложения блокировок....... 220 10.1.2 Взаимоблокировки, вызванные динамическим порядком блокировок 221 10.1.3 Взаимоблокировки между взаимодействующими объектами ............... 225 10.1.4 Открытые вызовы ...................................................................................... 226 10.1.5 Взаимоблокировки ресурсов .................................................................... 229 10.2 Предотвращение и диагностика взаимоблокировок...................................... 229 10.2.1 Блокировки, ограниченные по времени ................................................... 230 10.2.2 Анализ взаимоблокировок с использованием дампов потоков ............. 230 10.3 Прочие угрозы живучести ............................................................................... 232 10.3.1 Голодание ................................................................................................... 232 10.3.2 Плохая отзывчивость ................................................................................ 233 10.3.3 Динамическая взаимоблокировка ............................................................ 234 10.4 Итоги .................................................................................................................. 234 Глава 11 Производительность и масштабируемость ................................................. 236 11.1 Размышления о производительности .............................................................. 236 11.1.1 Производительность и масштабируемость ............................................. 237 11.1.2 Оценка компромиссов производительности ........................................... 238 11.2 Закон Амдала .................................................................................................... 240 11.2.1 Пример: скрытое последовательное выполнение в фреймворках ......... 243 11.2.2 Качественное применение закона Амдала .............................................. 244 11.3 Затраты, вводимые потоками .......................................................................... 245 11.3.1 Переключение контекста .......................................................................... 245 11.3.2 Синхронизация памяти ............................................................................. 246 11.3.3 Блокирование ............................................................................................. 247 11.4 Уменьшение конкуренции за блокировку ...................................................... 248 11.4.1 Сужение области действия блокировки (“Get in, get out”) .................... 249 11.4.2 Уменьшение детализации блокировки .................................................... 251 11.4.3 Чередование блокировок .......................................................................... 253 11.4.4 Как избежать использования “горячих полей” ....................................... 254 11.4.5 Альтернативы монопольным блокировкам ............................................. 255 11.4.6 Мониторинг использования CPU ............................................................. 256 11.4.7 Просто скажите “нет” помещению объектов в пул ................................ 257 11.5 Пример: Сравнение производительности реализаций Map .......................... 258 11.6 Сокращение накладных расходов на переключение контекста ................... 260 11.7 Итоги .................................................................................................................. 261 Глава 12 Тестирование параллельных программ ...................................................... 263 12.1 Тестирование на корректность ........................................................................ 264 12.1.1 Простые модульные тесты ........................................................................ 265 12.1.2 Тестирование блокирующих операций ................................................... 266 12.1.3 Тестирование безопасности ...................................................................... 268 12.1.4 Тестирование управления ресурсами ...................................................... 272 12.1.5 Использование обратных вызовов ........................................................... 274 12.1.6 Увеличение степени чередования ............................................................ 275 12.2 Тестирование производительности ................................................................. 276 12.2.1 Расширение класса PutTakeTest с добавлением учёта времени ............ 276 12.2.2 Сравнение нескольких алгоритмов .......................................................... 279 12.2.3 Измерение отзывчивости .......................................................................... 280 12.3 Как избежать ошибок тестирования производительности ........................... 282 12.3.1 Сборка мусора ............................................................................................ 282 12.3.2 Динамическая компиляция ....................................................................... 283 12.3.3 Нереалистичная выборка веток выполнения кода .................................. 284 12.3.4 Нереалистичные предположения о степенях конкуренции ................... 285 12.3.5 Устранение мёртвого кода ........................................................................ 285 12.4 Комплементарные подходы к тестированию ................................................. 287 12.4.1 Ревю кода ................................................................................................... 287 12.4.2 Инструменты для проведения статического анализа ............................. 288 12.4.3 Аспектно-ориентированные подходы к тестированию .......................... 290 12.4.4 Профилировщики и инструменты мониторинга ..................................... 290 12.5 Итоги .................................................................................................................. 290 Часть IV Дополнительные темы ................................................................................. 292 Глава 13 Явные блокировки ........................................................................................ 293 13.1 Интерфейсы Lock и ReentrantLock .................................................................. 293 13.1.1 Опрашиваемый и ограниченный по времени захват блокировки ......... 294 13.1.2 Прерываемый захват блокировки ............................................................ 296 13.1.3 Блокировка с не-блочной структурой ...................................................... 297 13.2 Вопросы производительности ......................................................................... 298 13.3 Справедливость................................................................................................. 299 13.4 Выбор между synchronized и ReentrantLock ................................................... 301 13.5 Блокировки на чтение-запись .......................................................................... 302 13.6 Итоги .................................................................................................................. 305 Глава 14 Разработка собственных синхронизаторов ................................................. 306 14.1 Управление зависимостью от состояния ........................................................ 306 14.1.1 Пример: распространение сбоев предусловий на вызывающий код .... 308 14.1.2 Пример: грубая блокировка путем опроса и сна .................................... 310 14.1.3 Очереди условий на освобождение .......................................................... 311 14.2 Использование очередей условий ................................................................... 313 14.2.1 Предикат условия ...................................................................................... 313 14.2.2 Раннее пробуждение .................................................................................. 314 14.2.3 Пропущенные сигналы.............................................................................. 316 14.2.4 Уведомление .............................................................................................. 316 14.2.5 Пример: класс затвора ............................................................................... 318 14.2.6 Вопросы безопасности подклассов .......................................................... 319 14.2.7 Инкапсулирование очередей условий...................................................... 320 14.2.8 Протоколы входа и выхода ....................................................................... 321 14.3 Явные объекты условия ................................................................................... 321 14.4 Анатомия синхронизатора ............................................................................... 324 14.5 Класс AbstractQueuedSynchronizer .................................................................. 326 14.5.1 Простая защёлка ........................................................................................ 328 14.6 AQS в классах-синхронизаторах из пакета java.util.concurrent .................... 329 14.6.1 Класс ReentrantLock................................................................................... 329 14.6.2 Классы Semaphore и CountDownLatch ..................................................... 330 14.6.3 Класс FutureTask ........................................................................................ 331 14.6.4 Класс ReentrantReadWriteLock ................................................................. 332 14.7 Итоги .................................................................................................................. 332 Chapter 15 Атомарные переменные и неблокирующая синхронизация .................. 333 15.1 Недостатки блокировки ................................................................................... 333 15.2 Аппаратная поддержка параллелизма ............................................................ 335 15.2.1 Сравнить и обменять ................................................................................. 335 15.2.2 Неблокирующий счётчик .......................................................................... 337 15.2.3 Поддержка операций CAS в среде JVM .................................................. 338 15.3 Классы атомарных переменных ...................................................................... 339 15.3.1 Atomics as “better volatiles” ....................................................................... 340 15.3.2 Производительность: блокировки против атомарных переменных ...... 341 15.4 Неблокирующие алгоритмы ............................................................................ 344 15.4.1 Неблокирующий стек ................................................................................ 344 15.4.2 Неблокирующий связанный список ......................................................... 346 15.4.3 Обновления атомарного поля ................................................................... 349 15.4.4 Проблема ABA ........................................................................................... 350 15.5 Итого .................................................................................................................. 351 Глава 16 Модель памяти Java ...................................................................................... 352 16.1 Что такое модель памяти и зачем она мне нужна? ........................................ 352 16.1.1 Основа моделей памяти ............................................................................ 353 16.1.2 Переупорядочивание ................................................................................. 354 16.1.3 О модели памяти Java менее чем в 500 словах ....................................... 355 16.1.4 Комбинирование в синхронизации .......................................................... 357 16.2 Публикация ....................................................................................................... 360 16.2.1 Небезопасная публикация ......................................................................... 360 16.2.2 Безопасная публикация ............................................................................. 361 16.2.3 Идиомы безопасной инициализации ....................................................... 362 16.2.4 Блокировка с двойной проверкой ............................................................ 363 16.3 Безопасность инициализации .......................................................................... 364 16.3 Итоги .................................................................................................................. 366 Приложение A Описание аннотаций .......................................................................... 367 A.1 Аннотации уровня классов ............................................................................... 367 A.2 Аннотации уровня полей и методов ................................................................ 367 Библиография ............................................................................................................... 369 Предисловие Только сейчас, когда пишется книга, многоядерные процессоры стали достаточно доступными, для использования в настольных системах среднего уровня. Не случайно, что множество команд разработчиков в своих проектах получают всё больше и больше отчётов об ошибках, связанных с потоками. В недавнем посте, на сайте разработчиков NetBeans, один из ключевых мэйнтейнеров (maintainers) отметил, что единственный класс был поправлен более 14 раз, для исправления проблем, связанных с потоками. Дин Алмайер, бывший редактор TheServerSide, недавно написал в своём блоге (после мучительной сессии отладки, в конечном итоге выведшей к ошибке с потоками), что в большинстве Java-программ так распространены ошибки многопоточности, что они работают только “случайно”. В самом деле, разработка, тестирование и отладка многопоточных программ может быть исключительно трудной, потому что ошибки параллельности проявляют себя непредсказуемо. И когда они всплывают на поверхность, это часто происходит в наихудший из возможных моментов времени – в продуктиве, под большой нагрузкой. Одним из вызовов в разработке параллельных программ на Java, является несоответствие между возможностями параллелизма, предлагаемыми платформой и тем, как разработчики вынуждены думать о параллельности в своих программах. Язык предоставляет низкоуровневые механизмы, такие как синхронизация (synchronization) и условие ожидания (condition waits), но эти механизмы должны использоваться согласованно, для реализации протоколов или политик уровня приложения. Без таких политик очень просто создавать программы, которые компилируются и представляются работающими, но, тем не менее, содержат ошибки. Множество других превосходных книг о параллельности не достигают своей цели, фокусируясь на низкоуровневых механизмах и API, а не на политиках и шаблонах уровня проектирования. В Java 5.0 был сделан гигантский шаг вперёд в разработке параллельных приложений Java, предоставляя новые, высокоуровневые компоненты, и дополнительные, низкоуровневые механизмы, что одинаково упростило построение параллельных приложений, как для новичков, так и для экспертов. Авторы являются основными членами экспертной группы JCP, создавшей эти средства; в дополнение, к описанию их поведения и возможностей, мы представляем лежащие в основе шаблоны проектирования и ожидаемые сценарии использования, что мотивировало их включение в библиотеки платформы. Мы ставили себе цель дать пользователю набор правил проектирования и мыслительных моделей, которые делают проще, – и веселее - построение корректных, производительных параллельных классов и приложений Java. Мы надеемся, что вам понравится книга Java Concurrency in Practice. Brian Goetz Williston, VT March 2006 Как читать эту книгу Для устранения абстрактного несоответствия между низкоуровневыми механизмами Java и необходимыми политиками уровня проектирования, мы представили упрощённый набор правил для написания параллельных программ. Эксперты могут посмотреть на эти правила и сказать, - “Хмм, это не совсем так: класс C потокобезопасен, даже если он нарушает правило R”. Хотя возможно писать корректные программы, нарушающие наши правила, это требует глубокого понимания низкоуровневых деталей модели памяти Java (Java Memory Model), и мы хотели, чтобы разработчики имели возможность писать корректные параллельные программы, без необходимости освоения этих деталей. Последовательное следование нашим упрощенным правилам позволит создавать правильные и сопровождаемые параллельные программы. Мы предполагаем, что читатель уже в некоторой степени знаком с базовыми механизмами параллелизма в Java. Java Concurrency in Practice не является введением в тему параллелизма – для этого, смотрите главу о потоках любого достойного талмуда, такого как The Java Programming Language (Arnold et al., 2005). И это не энциклопедический справочник для всех вещей параллелизма – за этим обращайтесь к Concurrent Programming in Java (Lea,2000). Напротив, книга предлагает практические правила проектирования, помогающие разработчикам в таком сложном процессе, как создание безопасных и производительных параллельных классов. При необходимости, мы ссылаемся на соответствующие разделы из книг The Java Pro-gramming Language, Concurrent Programming in Java, The Java Language Specification (Gosling et al., 2005), and Effective Java (Bloch, 2001) используя сокращения [JPL n.m], [CPJ n.m], [JLS n.m], and [EJ Item n]. После введения (Глава 1), книга делится на четыре части: Основы. Часть I (Главы2 - 5) фокусируется на базовых концепциях параллелизма, потокобезопасности и на том, как составлять потокобезопасные классы из параллельных строительных блоков, предоставляемых библиотекой классов. “Шпаргалка” в разделе “Итоги части I” суммирует наиболее важные из правил, представленных в части I. Главы 2 (потокобезопасность) и 3 (совместно используемые объекты) формируют основу книги. Почти все правила позволяют избегать рисков параллелизма, конструировать потокобезопасные классы и проверять безопасность потоков. Читатели, предпочитающие “практику” вместо “теории”, могут поддаться соблазну перейти к части II, но должны обязательно вернуться к главам 2 и 3 до написания любого параллельного кода! Глава 4 (Компоновка объектов) покрывает техники для компоновки потокобезопасных классов в большие потокобезопасные классы. Глава 5 (Строительные блоки) покрывает тему параллельных строительных блоков - потокобезопасных коллекций и синхронизации - предоставляемых библиотекой платформы. Структурирование параллельных программ. В части II (Главы6-9) описывается, как эксплуатировать потоки для увеличения пропускной способности и отзывчивости параллельных приложений Глава 6 (Выполнение задач) затрагивает тему идентификации параллелизуемых задач и выполнения их внутри выполняющих задачи фрэймворков (task-execution framework). Глава 7 (Отмена and завершение) имеет дело с техниками убеждения задач и потоков завершаться до того, как они смогут это сделать нормально; то, как программы имеют дело с отменой и завершением, часто является одним из факторов, который отделяет действительно надёжные параллельные приложения от тех, что просто работают. В главе 8 (Применение пула потоков) рассматриваются некоторые более продвинутые возможности фреймворков выполнения задач. Глава 9 (Приложения GUI) фокусируется на техниках по повышению отзывчивости в однопоточных подсистемах. Жизнеспособность, производительность и тестирование. Часть III (Главы 10-12) заботятся о том, чтобы параллельные программы действительно делали то, что вы хотите, и делали это с приемлемой производительностью. Глава 10 (Как избежать угроз живучести) описывает, как предотвращать проблемы живучести, которые могут помешать программам, продвигаться вперёд. Глава 11 (Производительность и масштабируемость) описывает техники, для увеличения производительности и масштабируемости в параллельном коде. Глава 12 (Тестирование параллельных программ) рассматривает техники тестирования параллельного кода на предмет корректности и производительности. Дополнительные темы. Часть IV (Главы13-16) затрагивает темы, которые понравятся и будут интересны только опытным разработчикам: явные блокировки, атомарные переменные, неблокирующие алгоритмы, и разработка собственных синхронизаторов (custom synchronizers). Примеры кода В то время как множество концепций в этой книге применимы к версиям Java, предшествующим Java 5.0 и даже к не Java окружению, большинство примеров кода (и все утверждения о модели памяти Java) предполагают Java 5.0 или старше. Некоторые примеры кода могут использовать функции библиотеки, добавленные в Java 6. Примеры кода были сжаты для уменьшения размера и для выделения соответствующих частей. Полные версии примеров кода, а также дополнительные примеры и список опечаток, доступны на вебсайте книги http://www.javaconcurrencyinpractice.com Примеры кода делятся на три категории: “хорошие” примеры, “не очень хорошие” примеры и “плохие” примеры. Хорошие примеры иллюстрируют техники, которым необходимо следовать. Плохие примеры иллюстрируют техники, которые, определённо, не должны воспроизводиться, и они, чтобы дать ясно понять, что это токсичный код, представляются с иконкой “Mr. Yuk” 1 (см. листинг 1). Не очень хорошие примеры иллюстрируют техники, которые необязательно ошибочные, но являются хрупкими, рискованными или имеют плохую производительность, они помечаются иконкой “Mr. Could Be Happier”, как показано в листинге 2. public // Never returns the wrong answer! System.exit(0); } Листинг 1. Плохой способ сортировки списка. Не делайте так! Некоторые читатели могут задать вопрос о роли плохих примеров в этой книге; в конце концов, книга должна показать, как делать все правильно, а не ошибаться. Плохие примеры преследуют две цели. Они иллюстрируют наиболее часто встречающие подводные камни, но, что более важно, они демонстрируют, как анализировать программы на потокобезопасность, и лучший путь сделать это, это увидеть пути, которые приводят к тому, что потокобезопасность компрометируется. public Collections.sort(list); } Листинг 2. Не самый оптимальный способ сортировки списка 1 Mr. Yuk является зарегистрированной торговой маркой детского госпиталя в Питсбурге и используется с разрешения. Часть I Основы |