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

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

Процессы и потоки

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

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

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

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

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

Запуск темы

Два способа начать обсуждение:

Предоставьте работающий объект
 общественный учебный класс HelloRunnable орудия Работоспособен {    @Override    общественный пустота пробег() {        Система.из.println("Привет из ветки!");    }    общественный статический пустота главный(Нить[] аргументы) {        (новый Нить(новый HelloRunnable())).Начните();    } }
Поток подкласса
 общественный учебный класс HelloThread расширяет Нить {    @Override    общественный пустота пробег() {        Система.из.println("Привет из ветки!");    }    общественный статический пустота главный(Нить[] аргументы) {        (новый HelloThread()).Начните();    } }

Прерывания

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

Присоединяется

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

Исключения

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Заключительные поля

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

История

С JDK 1.2, Java включает стандартный набор классов коллекций, Фреймворк коллекций Java

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

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

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

Смотрите также

Примечания

  1. ^ Oracle. "Интерфейс Thread.UncaughtExceptionHandler". Получено 10 мая 2014.
  2. ^ «Смерть тихой нити из-за необработанных исключений». literatejava.com. Получено 10 мая 2014.
  3. ^ Херлихи, Морис и Нир Шавит. «Искусство многопроцессорного программирования». PODC. Vol. 6. 2006.
  4. ^ Раздел 17.4.4: Порядок синхронизации«Спецификация языка Java®, Java SE 7 Edition». Корпорация Oracle. 2013. Получено 2013-05-12.
  5. ^ Дуг Ли. "Обзор пакета util.concurrent Release 1.3.4". Получено 2011-01-01. Примечание. После выпуска J2SE 5.0 этот пакет переходит в режим обслуживания: будут выпущены только существенные исправления. Пакет J2SE5 java.util.concurrent включает улучшенные, более эффективные, стандартизированные версии основных компонентов в этом пакете.

Рекомендации

внешняя ссылка