Модель памяти Java
JMM (модель памяти Java) — это модель памяти, определенная JVM для защиты различий в доступе к памяти различного оборудования и операционных систем.
- Основная память: Все переменные хранятся в основной памяти (Main Memory, аналог физической памяти).
- Рабочая память: Каждый поток имеет свою собственную рабочую память (Рабочая память, аналогичная кешу процессора).В рабочей памяти потока хранится копия основной памяти, копия переменной, используемой потоком, и все операции над переменной, выполняемые поток (чтение, выборка, присваивание и т. д.) должен выполняться в рабочей памяти, а переменные в основной памяти не могут быть напрямую прочитаны и записаны. Разные потоки не могут напрямую обращаться к переменным в рабочей памяти друг друга, а передачу значений переменных между потоками нужно делать через основную память.
Взаимодействие между памятью
- lock: переменная, которая воздействует на основную память и идентифицирует переменную как состояние монопольного потока.
- разблокировать (разблокировать): переменная, действующая на основную память, она освобождает переменную в заблокированном состоянии, а освобожденная переменная может быть заблокирована другими потоками.
- read (чтение): переменная, действующая на основную память, которая передает значение переменной из основной памяти в рабочую память потока для последующих действий загрузки.
- load: переменная, воздействующая на рабочую память, которая помещает значение переменной, полученное операцией чтения из основной памяти, в переменную копию рабочей памяти.
- использование: переменная, которая воздействует на рабочую память, которая передает значение переменной в рабочей памяти механизму выполнения, который будет выполняться всякий раз, когда виртуальная машина встречает инструкцию байт-кода, которая должна использовать значение переменной.
- assign (назначение): переменная, которая воздействует на рабочую память, она присваивает значение, полученное от механизма выполнения, переменной в рабочей памяти, и выполняет эту операцию всякий раз, когда виртуальная машина встречает инструкцию байт-кода, которая присваивает значение переменной.
- store (хранение): переменная, действующая на рабочую память, которая передает значение переменной из рабочей памяти в основную память для последующих операций записи.
- write (запись): переменная, действующая на основную память, которая помещает значение переменной, полученное из рабочей памяти операцией сохранения, в переменную основной памяти.
Среди них чтение и загрузка, сохранение и запись должны использоваться парами, а порядок должен выполняться непрерывно. С точки зрения непрофессионала, после выполнения чтения загрузка будет выполнена позже, но не обязательно загружать сразу после чтения; то же самое верно для сохранения и записи. Блокировка и разблокировка также отображаются парами, и переменная может быть заблокирована только одним потоком одновременно.
-
Для операций с обычными переменными: Чтобы создать переменную, она инициализируется в основной памяти. Переменные, используемые потоками, сначала копируются из основной памяти (
read
) выйти, загрузить (load
) в рабочую память, затем ссылка (use
) переменная и вычислить присвоение (assign
). затем сохранить(store
) в рабочую память, затем обновить (write
), чтобы удалить исходную переменную.Передачу значения обычных переменных между потоками нужно делать через основную память. Например, поток A изменяет значение общей переменной, а затем записывает обратно в основную память.Другой поток B читает из основной памяти после завершения обратной записи потока A, и новое значение переменной становится видимым для потока B.
-
за
volatile
Модифицированные переменные: Процедуры такие же, как и для обычных переменных. Однако видимость переменных гарантируется для всех потоков, а оптимизации для переупорядочивания инструкций отключены.Специальные правила volatile гарантируют, что новые значения немедленно синхронизируются с основной памятью и сбрасываются из основной памяти непосредственно перед каждым использованием. Поэтому можно сказать, что volatile гарантирует видимость переменных при многопоточных операциях, а обычные переменные этого не гарантируют.
Принцип «случается раньше»
Это основная основа для суждения о том, есть ли конкуренция в данных и является ли поток безопасным.Опираясь на этот принцип, мы можем решить все проблемы, связанные с тем, могут ли быть конфликты между двумя операциями в параллельной среде с помощью нескольких правил.
Возникновение до — это отношение частичного порядка между двумя операциями, определенными в модели памяти Java. Если операция А выполняется первой перед операцией Б, это фактически означает, что до того, как произойдет операция Б, эффект операции А можно наблюдать с помощью операции Б. " включает изменение значения общей переменной в памяти, отправку сообщения, вызов метода и т. д.
нить
Поток является более легкой исполнительной единицей планирования, чем процесс. Введение потока может разделить распределение ресурсов и планирование выполнения процесса. Каждый поток может совместно использовать ресурсы процесса (адрес памяти, файловый ввод-вывод и т. д.) и может быть независимым Планирование (поток является основной единицей планирования ЦП).
3 способа реализации потоков:
- Реализовано с использованием потоков ядра
- Поток ядра (Kernel-Level Thread, KLT) — это поток, непосредственно поддерживаемый ядром операционной системы (Kernel, в дальнейшем именуемый ядром) и отвечающий за сопоставление задачи потока с каждым процессором. Каждый поток ядра можно рассматривать как аватар ядра, так что операционная система имеет возможность обрабатывать несколько вещей одновременно Ядро, поддерживающее многопоточность, называется многопоточным ядром (Multi-Threads Kernel). .
- Программы обычно используют не потоки ядра напрямую, а легковесные процессы (потоки в популярном смысле). эти двое
1:1
Переписка. Создание, синхронизация вызовов и т. д. выполняются системой, которая является дорогостоящей (ей необходимо переключаться между режимом ядра и режимом пользователя), и каждый легкий процесс потребляет определенные ресурсы ядра (например, пространство стека потоков ядра). ), поэтому облегченные процессы, поддерживаемые системой, ограничены.
- Реализовано с использованием пользовательских потоков
- Вообще говоря, поток можно считать пользовательским потоком, если он не является потоком ядра. Поэтому легковесные процессы тоже относятся к пользовательским потокам, но реализация легковесных процессов всегда основана на ядре, а многие операции требуют системных вызовов, что ограничивает эффективность.
- В узком смысле под пользовательским потоком понимается реализация, полностью построенная на библиотеке потоков в пользовательском пространстве, и ядро системы не может воспринимать существование потоков. Создание, синхронизация, уничтожение и планирование пользовательских потоков полностью выполняются в пользовательском режиме без помощи ядра. Если программа реализована правильно, этому потоку не нужно переключаться в состояние ядра, поэтому операция может быть очень быстрой и малозатратной, а также может поддерживать большее количество потоков.Многопоточность в некоторых высокопроизводительных базах данных реализована с помощью пользовательские темы. между таким процессом и пользовательским потоком
1:N
Отношения называются моделью многопоточности «один ко многим». - Преимущество использования пользовательских потоков состоит в том, что оно не требует поддержки системного ядра, а недостатком является отсутствие поддержки системного ядра. Все операции с потоками должны обрабатываться самой пользовательской программой, а реализация будет очень сложной, поэтому сейчас используется редко.
- Смешанная реализация с использованием пользовательских потоков и облегченных процессов
- Существуют как пользовательские потоки, так и легковесные процессы. Пользовательские потоки по-прежнему полностью встроены в пользовательское пространство, поэтому такие операции, как создание, переключение и уничтожение пользовательских потоков по-прежнему дешевы, и может поддерживаться крупномасштабный параллелизм пользовательских потоков. Облегченный процесс, поддерживаемый операционной системой, действует как мост между пользовательскими потоками и потоками ядра, так что можно использовать функцию планирования потоков и сопоставление процессоров, предоставляемые ядром, а системные вызовы пользовательских потоков должны выполняться через облегченные потоки. , что значительно снижает риск полной блокировки всего процесса. В этом гибридном режиме отношение количества пользовательских потоков к легковесным процессам неопределенно, т. е.
N:M
Это модель многопоточности «многие ко многим».
- Существуют как пользовательские потоки, так и легковесные процессы. Пользовательские потоки по-прежнему полностью встроены в пользовательское пространство, поэтому такие операции, как создание, переключение и уничтожение пользовательских потоков по-прежнему дешевы, и может поддерживаться крупномасштабный параллелизм пользовательских потоков. Облегченный процесс, поддерживаемый операционной системой, действует как мост между пользовательскими потоками и потоками ядра, так что можно использовать функцию планирования потоков и сопоставление процессоров, предоставляемые ядром, а системные вызовы пользовательских потоков должны выполняться через облегченные потоки. , что значительно снижает риск полной блокировки всего процесса. В этом гибридном режиме отношение количества пользовательских потоков к легковесным процессам неопределенно, т. е.
Реализация потоков Java: до JDK1.2 существовали пользовательские потоки, а версии 1.2 и более поздние использовали собственную модель потоков операционной системы (поток ядра).
Планирование потоков Java
Планирование потоков относится к процессу, в котором система назначает права использования процессора потокам.Существует два основных метода планирования:
- Кооперативное планирование потоков: время выполнения потока контролируется самим потоком.После того, как поток завершил свою работу, он должен активно уведомить систему о переключении на другой поток.
- Преимущества: реализация проста, а поскольку перед переключением потока поток должен сделать что-то свое, операция переключения известна самому потоку, поэтому проблем с синхронизацией потоков не возникает.
- Недостаток: время выполнения потока неуправляемо, и даже если поток написан неправильно и системе не сказано выполнять переключение потоков, программа всегда будет там заблокирована.
- Упреждающее планирование потоков: каждому потоку система выделяет время выполнения, и переключение потоков не определяется самим потоком (в Java,
Thread.yield()
Можно отказаться от времени выполнения, но сам поток не может получить время выполнения). При таком способе реализации планирования потоков время выполнения потока контролируется системой, и нет проблем, что один поток вызывает блокировку всего процесса.Метод планирования потоков, используемый в Java, представляет собой вытесняющее планирование.
Хотя планирование Java-потоков выполняется системой автоматически, мы все же можем «посоветовать» системе выделять немного больше времени выполнения для одних потоков и немного меньше для других — путем установки приоритета потока (два потока находятся в состоянии «Готово» в одно и то же время) поток с более высоким приоритетом легче выбрать системой для выполнения), но этот метод не очень надежен, поскольку приоритет системного потока и приоритеты 10 потоков Java не обязательно совпадают один к одному.
состояние потока
В любой момент времени поток имеет только одно состояние
- Новый (Новый): Он не был запущен после создания
- Runable: выполняется или ожидает, пока ЦП выделит ему время выполнения.
- Ожидающий:
- Бесконечное ожидание (ожидание): потокам не выделяется время выполнения ЦП, ожидая явного пробуждения другими потоками.
- Ожидание по времени: потокам не будет выделяться время выполнения ЦП, и им не нужно ждать явного пробуждения другими потоками.Они будут автоматически пробуждены системой через определенный период времени.
- Заблокировано: заблокировано
- Разница между блокировкой и ожиданием:
阻塞状态
Во время ожидания получения эксклюзивной блокировки это событие произойдет, когда другой поток освободит блокировку; и等待状态
Это ожидание в течение определенного периода времени или возникновения действия пробуждения. Потоки входят в это состояние, пока программа ожидает входа в область синхронизации.
- Разница между блокировкой и ожиданием:
- Прекращено: Прекращено