Базовые знания многопоточности! После прочтения изучение многопоточности может сделать больше с меньшими затратами

Java задняя часть Операционная система Java EE

предисловие

Случайно, я не обновлялся несколько дней, и я пойду домой на этой неделе. Усердно работай в школьные дни!

Только лысина может стать сильнее

Оглядываясь назад на фронт:

Знания этой статьи в основном относятся к первым 4 главам книги «Java Concurrent Programming Practice» Первые 4 главы этой книги посвящены основам параллелизма. Если мы сможем хорошо понять эти основы, то наше будущее изучение будет более эффективным.

Конечно, «Параллельное программирование на Java на практике» можно назвать очень классической книгой.Я не могу полностью понять это, и я просто подбрасываю здесь некоторые идеи. Если вы хотите получить более полное представление о тех знаниях, которые я упомянул ниже, вы можете прочитать эту книгу, которая в целом хороша.

Во-первых, давайте посмотрим, о чем говорится в первых 4 главах «Java Concurrent Programming Practice»:

Глава 1 Введение

  • 1.1 Краткая история параллелизма
  • 1.2 Преимущества резьбы
  • 1.2.1 Раскройте потенциал мультипроцессоров
  • 1.2.2 Простота моделирования
  • 1.2.3 Упрощенная обработка асинхронных событий
  • 1.2.4  Более отзывчивый пользовательский интерфейс
  • 1.3 Риски, связанные с потоками
  • 1.3.1 Вопросы безопасности
  • 1.3.2  Проблема живучести
  • 1.3.3 Проблемы с производительностью
  • 1.4 Треды повсюду

пс:я не буду говорить об этой части, главным образом, чтобы выявить наши следующие точки знаний, и заинтересованные студенты могут прочитать оригинальную книгу ~

Глава 2. Потокобезопасность

  • 2.1 Что такое потокобезопасность
  • 2.2 Атомарность
  • 2.2.1 УСЛОВИЯ ГОНКИ
  • 2.2.2  Пример: Состояние гонки при ленивой инициализации
  • 2.2.3 Композитная операция
  • 2.3 Запорный механизм
  • 2.3.1 Встроенный замок
  • 2.3.2 Реентерабельность
  • 2.4 Защитить состояние блокировками
  • 2.5 Активность и производительность

Глава 3 - Совместное использование объектов

  • 3.1 Видимость
  • 3.1.1  Данные об отказах
  • 3.1.2 Неатомарные 64-битные операции
  • 3.1.3 Блокировка и видимость
  • 3.1.4 Волатильная переменная
  • 3.2 Выпуск и побег
  • 3.3 Закрытие резьбы
  • 3.3.1 Специальное закрытие резьбы
  • 3.3.2  Закрытие стека
  • 3.3.3 Класс ThreadLocal
  • 3.4 Неизменяемость
  • 3.4.1 Последнее поле
  • 3.4.2  Пример: использование изменчивых типов для публикации неизменяемых объектов
  • 3.5 Выпуск системы безопасности
  • 3.5.1  Неправильный выпуск: правильный объект уничтожен
  • 3.5.2  Неизменяемые объекты и безопасность инициализации
  • 3.5.3 Общие режимы безопасного выпуска
  • 3.5.4 Неизменяемые объекты фактов
  • 3.5.5  Изменяемые объекты
  • 3.5.6 Безопасный обмен объектами

Глава 4 - Состав объектов

  • 4.1  Разработка потокобезопасных классов
  • 4.1.1 Сбор требований к синхронизации
  • 4.1.2 Операции, зависящие от состояния
  • 4.1.3 Право собственности на государство
  • 4.2 Закрытие экземпляра
  • 4.2.1 Режим монитора Java
  • 4.2.2  Пример: отслеживание транспортных средств
  • 4.3 Поточно-безопасное делегирование
  • 4.3.1  Пример: средство отслеживания транспортных средств на основе делегирования
  • 4.3.2 Независимые переменные состояния
  • 4.3.3 Если делегирование не удается
  • 4.3.4 Опубликовать базовые переменные состояния
  • 4.3.5  Пример: статус публикации средства отслеживания транспортных средств
  • 4.4 Добавить функциональность в существующие потокобезопасные классы
  • 4.4.1 Механизм блокировки клиента
  • 4.4.2 Комбинация
  • 4.5  Задокументируйте стратегию синхронизации

Тогда начнем~

1. Проблемы, возникающие при использовании многопоточности

1.1 Вопросы безопасности потоков

Тема описана в предыдущей статье [Вы можете войти в дверь за три минуты с многопоточностью!], многопоточность в основном предназначена для улучшенияиспользование приложения. Но в то же время это даст намприносит много проблем с безопасностью!

если бы мы былиодин потокВыполнять код "последовательно" (последовательно --> монопольно)нет проблемиз. Но в многопоточной среде (параллельной), если она плохо спроектирована и не контролируется, это принесет нам многоНепредвиденные условия, а именно проблемы безопасности потоков

Поскольку в многопоточной среде потокиАльтернативное исполнениеДа, обычно они будут использовать несколько потоковвыполнить тот же код. Если в этом же коде естьобщая переменная, или несколькоОбъединить операцию, мы хотимправильныйВ результате легко могут возникнуть проблемы

Простой пример:

  • Следующая программа работает в одном потоке, проблем нет.

public class UnsafeCountingServlet extends GenericServlet implements Servlet {
    private long count = 0;

    public long getCount() {
        return count;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

        ++count;
        // To something else...
    }
}

Но при работе в многопоточной среде еговычисление значения счетчикаНе правильно!

Во-первых, этообщийпеременная count, а во-вторых++count;Этокомбинированные операции(Уведомление,это не атом)

  • ++countФактическая операция выглядит следующим образом:
    • прочитать значение счетчика
    • +1 значение
    • Запишите результат расчета для подсчета

Итак, при многопоточном выполненииСкорее всегоБудет что-то вроде этого:

  • Когда поток A считывает значение count равно 8,в то же времяПоток B также вошел в этот метод, а также прочитал значение count до 8
  • Оба они добавляют 1 к значению
  • Запишите результат расчета для подсчета. но,Результат, записанный для подсчета, равен 9
  • То есть: приходят два потока, ноПравильный результат состоит в том, что он должен вернуть 10, и он вернул 9, что ненормально!

Если вы скажете: когда несколько потоков обращаются к классу, этот классВсегдаМожет показатьправильное поведение, то класс является потокобезопасным!

Есть принцип:Если вы можете использовать механизм безопасности потоков, предоставляемый JDK, используйте JDK..

Конечно, эта часть на самом деле нашаСамая важная часть изучения многопоточности, я не буду вдаваться в подробности здесь. Это всего лишь обзор, эти точки знаний будут встречаться в более позднем обучении ~~~

1.3 Проблемы с производительностью

Цель использования многопоточности — улучшить использование приложения, но если многопоточный кодне хорошо разработанЕсли это так, это не обязательно повысит эффективность.Наоборот, это снижает эффективность и даже приводит к взаимоблокировке.!

Например, наш сервлет, объект сервлета, может обрабатывать несколько запросов,Сервлет, очевидно, является естественной поддержкой многопоточности..

Возьмем еще раз следующий пример:


public class UnsafeCountingServlet extends GenericServlet implements Servlet {
    private long count = 0;

    public long getCount() {
        return count;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

        ++count;
        // To something else...
    }
}

Из вышесказанного мы сказали вышеЭтот класс небезопасен для потоков. Самый простой способ: если добавить в сервисный метод встроенную синхронизацию блокировок, предоставляемую JDK, то можно добиться потокобезопасности.


public class UnsafeCountingServlet extends GenericServlet implements Servlet {
    private long count = 0;

    public long getCount() {
        return count;
    }

    public void synchronized service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

        ++count;
        // To something else...
    }
}

Хотя потокобезопасность достигается, этоСерьезная проблема с производительностью:

  • Каждый запрос долженждатьСервисный метод предыдущего запросапосле обработкивыполнить соответствующую операцию

Это приводит к: мы завершаем небольшую функцию, цель использования многопоточности — повысить эффективность, но теперьНе правильно, но вызывает серьезные проблемы с производительностью!

При использовании многопоточности: когда это более серьезно, естьтупик(Программа не может двигаться).

Это то, что мы узнаем дальше:Узнайте, какой механизм синхронизации использовать для обеспечения безопасности потоков, и производительность улучшится, а не уменьшится.~

2. Освобождение и побег объектов

Книга определяет освобождение и побег следующим образом:

publish (опубликовать) делает объект доступным в коде за пределами текущей области

escape (побег), когда публикуется объект, который не должен публиковаться

общийпобегСуществуют следующие способы:

  • выход из статического поля
  • общедоступный модифицированный метод получения
  • передача параметра метода
  • подразумевает это

Статическое поле выскакивает:

общедоступный модифицированный метод получения:

Я больше не буду демонстрировать передачу параметров метода, потому что передача объекта другому методу уже прошла~

Взгляните на книгу нижеэтот сбежавший пример:

Побег - это когда объект не должен выпускаться, а объект освобождается. привести к нашемуданные нарушенияout, что создаетРиски безопасности! Легко ли это понять?

2.1 Объекты выпуска безопасности

Есть несколько ситуаций побега, упомянутых выше, давайте поговорим об этом далее.Как безопасно публиковать объекты.

Существует несколько распространенных способов безопасной публикации объектов:

  • Прямая инициализация в статическом домене:public static Person = new Person();
    • Статическая инициализация выполняется JVM на этапе инициализации класса.Внутри JVM есть механизм синхронизации, чтобы таким образом мы могли безопасно опубликовать объект
  • Соответствующая ссылка сохраняется вvolatile или ссылка AtomicReferance
    • Гарантированная видимость и атомарность ссылок на этот объект
  • Изменено окончательным
    • Объект неизменяем, поэтому поток должен быть безопасным, поэтому его можно безопасно публиковать~
  • защищен замком
    • И выпуск, и использование должны быть заблокированы, чтобы гарантировать, что объект не ускользнет.

3. Решить проблемы, возникающие при многопоточности

Из вышеизложенного видно, что использование многопоточности сделает нашу систему довольно сложной. Это требует, чтобы мы имели дело со многими вещами, чтобы предотвратить проблемы с безопасностью и производительностью, которые приносит нам многопоточность~

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

3.1 Кратко опишите решение для обеспечения безопасности потоков

Необходимо использовать многопоточностьУбедитесь, что наша ветка безопасна, это самое важное место!

В Java у нас обычно есть следующие способы достижения безопасности потоков:

  • нет статуса(нет общих переменных)
  • Используйте Final, чтобы сделать ссылочную переменную неизменно (если ссылка на объект также ссылается на другие объекты, она должна быть заблокирована, когда он выпущен или используется)
  • Блокировка (встроенная блокировка, блокировка дисплея)
  • Используйте классы, предоставляемые JDK, для обеспечения безопасности потоков (в этом разделе много классов).
    • атомарность (как вышеcount++Operation, вы можете использовать AtomicLong для достижения атомарности, поэтому при добавлении не будет ошибки! )
    • Контейнеры (ConcurrentHashMap и т. д.)
    • ......
  • ...и т.д

3.2 Атомарность и видимость

Что такое атомарность? Что такое видимость? я былConcurrentHashMap основан на анализе исходного кода JDK1.8.Коротко уже сказано. Студенты, которые не знают, могут войти и посмотреть.

3.2.1 Атомарность

Часто в многопоточности это происходит из-за того, что операция не является атомарной, что делает данные хаотичными и неправильными. Если обрабатываемые данные являются атомарными, проблем с безопасностью потоков можно избежать!

  • count++, сначала читать, потом автоинкрементировать, а потом уже присваивать.Если операция атомарная, то можно сказать, что она потокобезопасна (потому что нет трех промежуточных звеньев, один шаг [атомарность])~

атомарностьзаключается в выполненииОперация неделима, - как указано вышеcount++операция, это не атомарная операция, она разделена на три шага для выполнения этой операции~ -Пакет atomic в JDK предоставляет нам атомарные операции.~

Некоторые люди составили таблицу, чтобы классифицировать его, давайте посмотрим:

图片来源:https://blog.csdn.net/eson_15/article/details/51553338

Операции, связанные с этими классами, также можно посмотреть в его блоге:

3.2.2 Видимость

завидимостьJava предоставляет ключевое слово: волатильный для нас, чтобы использовать ~

  • Мы можем просто подумать: volatile — этоЛегкий механизм синхронизации

изменчивое классическое резюме:volatile используется только для обеспечения видимости переменной для всех потоков, но не гарантирует атомарности

Давайте разберем это, чтобы объяснить:

  • гарантироватьПеременные видимости всех потоков
    • В многопоточной среде: когда эта переменная изменяется,Все потоки будут знать, что переменная была изменена, так называемая "видимость"
  • Атомарность не гарантируется
    • Изменить переменную (назначить)по сутинаходится в JVMнесколько шаговНа этих этапах (от загрузки переменных до модификации) небезопасно.

Переменные, украшенные volatileгарантировано три:

  • Как только вы закончите писать, любой поток, обращающийся к этому полю, получит самое последнее значение.
  • Прежде чем писать,гарантирует, что все, что произошло раньше, произошло, и любые обновленные значения данных также видны, потому что барьер памяти сбрасывает ранее записанные значения в кеш.
  • volatile предотвращает переупорядочивание(Переупорядочение означает: когда программа выполняется, ЦП и компилятор могутВнесите некоторые коррективы в порядок выполнения, порядок выполнения не сверху вниз. что приводит к неожиданным эффектам). И если объявлено volatile, то процессор и компилятор будут знатьЭта переменная является общей, не будет кэшироваться в регистрах или других невидимых местах.

Вообще говоря,Volatile в основном используется для флагов (оценочные операции).Волатильные переменные должны использоваться только в том случае, если выполнены следующие условия:

  • Изменение переменной не зависит от текущего значения переменной(потому что volatile не гарантирует атомарность)
  • Переменная не будет включена в условие инвариантности(переменная изменяемая)
  • Не нужно блокировать при доступе к переменным(Нет необходимости использовать легкий механизм синхронизации, такой как volatile для блокировки)

Использованная литература:

3.3 Закрытие резьбы

В многопоточной среде, пока мыПеременные-члены не используются (данные не используются совместно), тогда проблем с потокобезопасностью не будет.

Возьмем в качестве примера знакомый сервлет. Мы написали так много сервлетов. Вы когда-нибудь видели, чтобы мы говорили, что нам нужна блокировка? ? Все наши данные оперируют методами (замыкание стека),Каждый поток имеет свои переменные и не мешает друг другу!

работать по методу,Пока мы следим за тем, чтобы не публиковать объекты в стеке (методы)(область действия каждой переменной остается только в текущем методе), тогда наш поток безопасен

Есть еще один метод закрытия потока, о котором я писал ранее:ThreadLocal так просто

Вы можете использовать API этого класса дляУбедитесь, что каждый поток имеет свою собственную эксклюзивную переменную. (Для получения дополнительной информации, пожалуйста, прочитайте статью выше) ~

3.4 Неизменяемость

Неизменяемые объекты определенно потокобезопасны.

Переменные, которыми мы поделились выше, все изменяемы, и именно из-за того, что они изменяемы, возникают проблемы с безопасностью потоков. еслиСостояние неизменно,ТакДоступ несколькими потоками не проблема!

Java предоставляет финальный модификатор, который мы можем использовать.Мы можем увидеть больше окончательных цифр, но стоит пояснить, что:

  • final — это просто ссылка, которая не может изменить переменную, но данные в ссылке могут быть изменены!

Если следующий HashMap, с окончательной модификацией. Он лишь гарантирует, чтоссылка на объектhashMap变量Указатель неизменяем, но данные внутри hashMap являются переменными, то есть: вы можете добавлять, удалять и т.д. в коллекцию~~~

  • Поэтому объяснить можно толькоhashMap — это неизменяемая ссылка на объект.

  final HashMap<Person> hashMap = new HashMap<>();

Ссылка на неизменяемый объектвсе еще используетсянужно заблокироватьиз

  • Или спроектируйте Person как потокобезопасный класс~
  • Поскольку внутреннее состояние изменчиво,Нет блокировки или Person не является потокобезопасным классом, операция опасна!

Чтобы создать неизменяемый объект, необходимо выполнить три условия:

  • Состояние объекта не может быть изменено после его создания
  • Все поля объекта являются окончательными
  • Объект создан правильно(эта ссылка не экранируется)

Строка в процессе нашего обучения мы знаем, что этонеизменяемый объект, но это не следует второму пункту (все поля объекта являются окончательными), потому что JVM оптимизирует его внутренне. Но если мы хотим сами создавать неизменяемые объекты, нам нужно выполнить три условия.

3.5 Поточно-безопасное делегирование

Много раз мы хотели добиться безопасности потоковВам не обязательно запирать его самостоятельно, вы можете спроектировать его сами.

Мы можем использовать объекты, предоставленные нам JDK, для завершения проектирования потокобезопасности:

Мы можем использовать множество «инструментальных классов», которые будут представлены в будущем обучении~~ Я не буду их здесь представлять.

Четвертый, последний

Правильное использование многопоточности может повысить эффективность нашего приложения, но принесет нам много проблем, на которые нужно обратить внимание перед использованием многопоточности.

Будь то неизменность, видимость, атомарность, закрытие потока, делегирование — все это способы достижения безопасности потока.означает. Чтобы разумно использовать эти средства, наша программа может быть более надежной!

Можно обнаружить, что упомянутое выше во многих местах:Замок. Но я не представил его, потому что я намеревалсяоставайся в следующем постеПриходите и пишите, пожалуйста, ждите этого~~~

Объяснение первых 4 глав книги заняло 65 страниц, и я использовал только одну статью для подведения итогов, чего далеко недостаточно.Студенты, которые хотят пойти дальше, могут прочитать книгу~

Когда я раньше изучал операционную систему, я также сделал небольшую заметку на основе книги «Компьютерная операционная система — Тан Сяодань», все из которых относительнопростое знание. Может всем поможет

Использованная литература:

  • «Основная технология Java, том 1»
  • «Практика параллельного программирования на Java»
  • «Компьютерная операционная система — Тан Сяодань»

Если в статье есть какие-либо ошибки, пожалуйста, поправьте меня, и мы сможем общаться друг с другом. Учащиеся, привыкшие читать технические статьи в WeChat и желающие получить больше ресурсов по Java, могутОбратите внимание на публичный аккаунт WeChat: Java3y. Спасибо за Вашу поддержку! Надеюсь представить больше другим нуждающимся друзьям

img

Проект с открытым исходным кодом, охватывающий все точки знаний о бэкэнде Java (уже 6 тысяч звезд):GitHub.com/Zhongf UC очень…

если ты хочешьв реальном времениЕсли вы обратите внимание на мои обновленные статьи и галантерейные товары, которыми я делюсь, поищите в WeChat.Java3y.

Содержимое PDF-документоввсе вручную, если вы ничего не понимаете, вы можете напрямуюспросите меня(В официальном аккаунте есть мои контактные данные).