Параллелизм Java

редактировать

Язык программирования Java и виртуальная машина Java (JVM) были разработаны для поддержки параллельного программирования, и все выполнение происходит в контексте потоков. Доступ к объектам и ресурсам может осуществляться многими отдельными потоками; каждый поток имеет свой собственный путь выполнения, но потенциально может получить доступ к любому объекту в программе. Программист должен гарантировать, что доступ для чтения и записи к объектам должным образом скоординирован (или "синхронизирован ") между потоками. Синхронизация потоков гарантирует, что объекты изменяются только одним потоком за раз и что потоки не могут получить доступ к частично обновленным объектам во время модификации другим потоком. В языке Java есть встроенные конструкции для поддержки такой координации.

Содержание
  • 1 Процессы и потоки
    • 1.1 Объекты потока
      • 1.1.1 Запуск потока
        • 1.1.1.1 Обеспечение выполняемого объекта
        • 1.1.1.2 Подкласс потока
      • 1.1.2 Прерывания
      • 1.1.3 Объединения
      • 1.1.4 Исключения
  • 2 Модель памяти
    • 2.1 Синхронизация
      • 2.1.1 Блокировки и синхронизированные блоки
      • 2.1.2 Энергозависимые поля
      • 2.1.3 Конечные поля
  • 3 История
  • 4 См. Также
  • 5 Примечания
  • 6 Ссылки
  • 7 Внешние ссылки
Процессы и потоки

Большинство реализаций виртуальной Java машина выполняется как единый процесс, а в языке программирования Java параллельное программирование в основном связано с потоками (также называемыми легковесными процессами ). Несколько процессов могут быть реализованы только с несколькими JVM.

Объекты потоков

Потоки совместно используют ресурсы процесса, включая память и открытые файлы. Это делает общение эффективным, но потенциально проблематичным. В каждом приложении есть хотя бы один поток, называемый основным потоком. Основной поток имеет возможность создавать дополнительные потоки как объекты Runnableили Callable. (Интерфейс Callableаналогичен интерфейсу Runnableв том, что оба они предназначены для классов, экземпляры которых потенциально выполняются другим потоком. A Runnable, однако, не возвращает результат и не может генерировать проверенное исключение.)

Каждый поток может быть запланирован на другом ядре ЦП или использовать квантование времени на одном аппаратном процессоре или квантование времени на многих аппаратных процессорах. Не существует универсального решения того, как потоки Java отображаются в собственные потоки ОС. Каждая реализация JVM может делать это по-своему.

Каждый поток связан с экземпляром класса Thread. Потоками можно управлять либо напрямую с помощью объектов Thread, либо с помощью абстрактных механизмов, таких как коллекции Executorи java.util.concurrent.

Запуск потока

Два способа запустить поток:

Предоставить запускаемый объект
открытый класс HelloRunnable реализует Runnable {@Override public void run () {System.out.println ("Привет из потока!"); } public static void main (String args) {(новый поток (новый HelloRunnable ())). start (); }}
Подкласс потока
открытый класс HelloThread расширяет поток {@Override public void run () {System.out.println ("Hello from thread!"); } public static void main (String args) {(new HelloThread ()). start (); }}

Прерывания

Прерывание - это указание потоку, что он должен остановить то, что он делает, и сделать что-то еще. Поток отправляет прерывание, вызывая прерывание для объекта Thread, чтобы поток был прерван. Механизм прерывания реализован с использованием внутреннего флага, известного как состояние прерывания. Вызов Thread.interruptустанавливает этот флаг. По соглашению, любой метод, который завершается путем выдачи исключения InterruptedException, при этом очищает состояние прерывания. Однако всегда возможно, что статус прерывания будет немедленно снова установлен другим потоком, вызывающим прерывание.

Объединяет

Методы Thread.joinпозволяют одному потоку ждать завершения другого.

Исключения

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

Модель памяти

Модель памяти Java описывает, как потоки в языке программирования Java взаимодействуют через память. На современных платформах код часто выполняется не в том порядке, в котором он был написан. Он переупорядочивается компилятором, процессором и подсистемой памяти для достижения максимальной производительности. Язык программирования Java не гарантирует линеаризуемость или даже последовательную согласованность при чтении или записи полей общих объектов, и это сделано для оптимизации компилятора ( такие как выделение регистров, исключение общего подвыражения и исключение избыточного чтения ), все из которых работают путем переупорядочения операций чтения-записи в памяти.

Синхронизация

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

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

Для синхронизации потоков Java использует мониторы, которые представляют собой высокоуровневый механизм, позволяющий только одному потоку одновременно выполнять область кода, защищенную монитором. Поведение мониторов объясняется с помощью блокировок ; с каждым объектом связана блокировка.

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

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

Чтение - запись в поля линеаризуема, если либо поле имеет значение volatile, либо поле защищено уникальной блокировкой, которая получена всеми читателями и писателями.

Блокировки и синхронизированные блоки

Поток может добиться взаимного исключения либо путем ввода синхронизированного блока или метода, который получает неявную блокировку, либо путем получения явной блокировки (например, ReentrantLock из пакет java.util.concurrent.locks). Оба подхода имеют одинаковые последствия для поведения памяти. Если все обращения к определенному полю защищены одной и той же блокировкой, то операции чтения-записи в это поле будут линеаризуемыми (атомарными).

Неустойчивые поля

При применении к полю Java volatileгарантирует, что:

  1. (во всех версиях Java) существует глобальный порядок чтения и записывает в изменчивую переменную. Это означает, что каждый поток , обращающийся к изменчивому полю, будет читать свое текущее значение перед продолжением вместо (потенциально) использования кэшированного значения. (Однако нет никакой гарантии относительно относительного упорядочения изменчивых операций чтения и записи с обычными операциями чтения и записи, что означает, что это, как правило, бесполезная конструкция потоковой передачи.)
  2. (В Java 5 или более поздней версии) Volatile считывает и записывает установить связь "происходит до", что очень похоже на получение и освобождение мьютекса. Эта взаимосвязь является просто гарантией того, что записи в память одним конкретным оператором будут видны другому конкретному оператору.

Изменяемые поля являются линеаризуемыми. Чтение изменчивого поля похоже на получение блокировки: рабочая память становится недействительной, и текущее значение изменчивого поля повторно считывается из памяти. Запись изменчивого поля похожа на снятие блокировки: изменчивое поле немедленно записывается обратно в память.

Конечные поля

Поле, объявленное как окончательное, не может быть изменено после его инициализации. Конечные поля объекта инициализируются в его конструкторе. Если конструктор следует некоторым простым правилам, то правильное значение любых полей final будет видно другим потокам без синхронизации. Правило простое: ссылка thisне должна выходить из конструктора до того, как конструктор вернется.

История

Начиная с JDK 1.2, Java включает стандартный набор классов коллекций, структуру коллекций Java

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

JDK 5.0 включает в себя множество дополнений и уточнений к модели параллелизма Java. API-интерфейсы параллелизма, разработанные JSR 166, также впервые были включены как часть JDK. JSR 133 обеспечивает поддержку четко определенных атомарных операций в многопоточной / многопроцессорной среде.

В выпусках Java SE 6 и Java SE 7 представлены обновленные версии API-интерфейсов JSR 166, а также несколько новых дополнительных API-интерфейсов.

См. Также
Примечания
Ссылки
Внешние ссылки
Последняя правка сделана 2021-05-24 03:57:45
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте