несколько небольших понятий
Критический ресурс: когда несколько потоков обращаются к одному и тому же объекту, этот объект называется критическим ресурсом.
Атомарные операции: операции, которые неделимы в критических ресурсах, называются атомарными операциями.
Небезопасный поток: несколько потоков одновременно обращаются к одному и тому же объекту, разрушая неразделимую операцию, и может возникнуть несогласованность данных.
Нить мир "сильные едят слабых"
Всем привет, меня зовут Ван Дачуй, и моя цель — стать генеральным директором... хм, извините за неправильный сценарий. Всем привет, меня зовут 0x7575, я тред, и мой идеал треда — получить процессор как можно скорее.
Позвольте мне сначала познакомить вас с миром потоков.Мир потоков - это мир джунглей, где ресурсов всегда мало, и все нужно хватать.Мне посчастливилось получить процессор за эти несколько наносекунд, и я добавил 1 к int a = 20. Вынул а из памяти, добавил 1 и потерял ЦП.Когда я был готов к записи в память после разрыва, я с удивлением обнаружил, что а в памяти стало 22 в в этот раз.
Должен быть какой-то поток, который модифицировал данные, пока меня не было, и я был в дилемме.Многие потоки также советовали мне не писать, но из-за инструкций я мог записать в память только 21, чтобы перезаписать 22, которые не соответствует моей операционной логике.
Вышеупомянутое — всего лишь небольшая авария.Подобные вещи происходят бесконечно в мире потоков, поэтому, хотя каждый поток из нас проявляет должную осмотрительность, в глазах людей мы являемся виновниками отсутствия безопасности данных.
Как это неправильно, мир потоков всегда был миром жесткой конкуренции, особенно за некоторые общие переменные, общие ресурсы (критические ресурсы), и это нормально, когда несколько потоков конкурируют за использование одновременно. Если общие ресурсы не будут устранены, что опять-таки невозможно, ситуация зайдет в тупик.
В мире потоков появляется замок
К счастью, кто-то умный и кто-то придумал хорошее решение проблемы. Хотя я не знаю, кто придумал внимание, это внимание действительно решает некоторые проблемы, и решениезамок.
Вы хотите работать с набором заблокированных кодов? Если вы хотите, возьмите замок первым.После того, как вы получите замок, вы можете делать все, что хотите с заблокированным кодом.Если вы не можете получить замок, вы можете только ждать у двери кодового блока, потому что есть слишком много ожидающих потоков становится социальным явлением (состоянием), которое называется блокировкой потока.
Звучит просто, но на самом деле существует множество подробных правил по запиранию.Для подробностей правительство издало «Несколько правил по использованию синхронизированных», а позже «Несколько правил по использованию замков».
Потоки разделяют память между потоками, и есть несколько проблем, которые неизбежны, когда несколько потоков работают с общей памятью, условиями гонки и видимостью памяти.
** Состояние гонки: ** Когда несколько потоков обращаются к одному и тому же объекту и работают с ним, окончательный результат зависит от времени выполнения, и правильность нельзя контролировать вручную, которая может быть или не быть правильной. (как в примере выше)
Упомянутая выше блокировка предназначена для решения этой проблемы.Обычные решения:
- Используйте синхронизированное ключевое слово
- Использовать явную блокировку (Lock)
- Используйте атомарные переменные
**Видимость памяти:** Что касается видимости памяти, мы должны начать с взаимодействия между памятью и ЦП. Память — это аппаратное обеспечение, и скорость ее выполнения в несколько сотен раз ниже, чем у ЦП. Поэтому в компьютере, когда Процессор выполняет операции, Он не взаимодействует с памятью для каждой операции, а сначала записывает некоторые данные в область кеша (регистры и все уровни кеша) в ЦП, и записывает их в память после окончания. Этот процесс чрезвычайно быстр, и с одним потоком проблем не возникает.
Однако при многопоточности возникает проблема: один поток изменяет кусок данных в памяти, но не записывает его в память вовремя (временно хранится в кеше), в это время другой поток изменяет те же данные. вы получаете в это время данные, которые не были изменены в памяти, то есть изменение общей переменной одним потоком не может быть немедленно замечено другим потоком или даже никогда не замечено.
Это проблема видимости памяти.
Распространенный способ решения этой проблемы:
- Используйте ключевое слово volatile
- Используйте ключевое слово synchronized или явную синхронизацию блокировки
синхронизация потоков
Традиционные замки синхронизированы
Блок синхронизированного кода
Каждый объект Java имеет метку блокировки мьютекса, которая используется для назначения потокам, synchronized(o){ } — это блок кода синхронизации, который блокирует o, и только поток, получивший метку блокировки, может ввести код синхронизации, который блокирует часть o. .
Синхронный метод
Метод, измененный с помощью модификатора synchronized в качестве модификатора метода, называется синхронизированным методом, который представляет синхронизированный блок кода, который блокирует это (весь метод является блоком кода).
Замок JDK1.5 Замок
ReentrantLock
ReentrantLock имеет функцию, аналогичную синхронизированной, но более гибкую и мощную.
Это реентерабельная блокировка (тоже синхронизированная).Так называемая реентерабельность означает, что вы можете многократно входить в одну и ту же функцию.Что толку от этого?
Предположим сценарий, рекурсивная функция, если блокировка функции разрешена только один раз, что должен делать поток, когда ему нужно рекурсивно вызвать функцию? Отступления нет, а есть функции, которые нельзя повторно ввести в блокировку, что формирует новый тупик.
Появление реентерабельных блокировок решает эту проблему, а метод достижения реентерабельности тоже очень прост: к блокировке добавляется счетчик.После того, как поток получает блокировку, счетчик будет увеличиваться на 1 каждый раз, когда он берет блокировку, и уменьшать 1 каждый раз, когда он снимается.Равно 0, тогда блокировка фактически снимается.
//创建一个锁对象
Lock lock = new ReentrantLock();
//上锁(进入同步代码块)
lock.lock();
//解锁(出同步代码块)
lock.unlock();
//尝试拿到锁,如果有锁就拿到,没有拿到不会阻塞,返回false
tryLock();
ReadWriteLock
Блокировка чтения-записи, разделение чтения-записи. Он разделен на две блокировки: readLock и writeLock. Для readLock это разделяемая блокировка, которую можно выделить несколько раз, но когда readLock заблокирован, вызов writeLock заблокирует, и наоборот.Кроме того, блокировка записи — это обычный мьютекс, который можно выделить только один раз.
Разница между синхронизированным и ReentrantLock
- Оба являются мьютексными блокировками, так называемыми мьютексными блокировками: только один поток, получивший блокировку, может одновременно обращаться к заблокированным общим ресурсам, а другие потоки могут только блокировать
- Все блокировки повторные, реализованные со счетчиками
- Уникальные возможности ReentrantLock
- ReenTrantLock может указать, является ли блокировка честной или несправедливой. А синхронизироваться может только несправедливая блокировка. Так называемая справедливая блокировка заключается в том, что поток, ожидающий первым, получает блокировку первым.
- ReenTrantLock предоставляет класс Condition, который используется для пробуждения потоков, которые необходимо активировать группами, а не пробуждать поток случайным образом или пробуждать все потоки, например синхронизированные.
- ReenTrantLock предоставляет механизм прерывания потоков, ожидающих блокировки, реализованный с помощью lock.lockInterruptably().
изменчивое ключевое слово
Модификатор volatile используется для обеспечения видимости
Когда общая переменная изменяется с помощью volatile, это гарантирует, что переменная будет обновлена в памяти сразу после ее изменения, и другой поток должен будет прочитать новое значение в памяти, когда он извлечет значение.
Примечание: Хотя volatile может гарантировать видимость переменных в памяти, она не может сохранить атомарность.Для b++ это не одношаговая операция, а разделена на несколько шагов, чтение переменных, определение константы 1, переменная b увеличивается на 1, и результат синхронизируется с памятью. Хотя на каждом шаге получается последнее значение переменной, атомарность b++ не гарантируется, и, естественно, невозможно добиться потокобезопасности.