Многопоточность Flashcards

1
Q

Дайте определение понятию “процесс”.

A

Процесс — это совокупность кода и данных, разделяющих общее виртуальное адресное пространство. Процессы изолированы друг от друга, поэтому прямой доступ к памяти чужого процесса невозможен (взаимодействие между процессами осуществляется с помощью специальных средств). Для каждого процесса ОС создает так называемое «виртуальное адресное пространство», к которому процесс имеет прямой доступ. Это пространство принадлежит процессу, содержит только его данные и находится в полном его распоряжении. Операционная система же отвечает за то, как виртуальное пространство процесса проецируется на физическую память.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Дайте определение понятию “поток”.

A

Один поток («нить» или «трэд») – это одна единица исполнения кода. Каждый поток последовательно выполняет инструкции процесса, которому он принадлежит, параллельно с другими потоками этого процесса.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Дайте определение понятию “синхронизация потоков”.

A

Синхронизация относится к многопоточности. Синхронизированный блок кода может быть выполнен только одним потоком одновременно.Java поддерживает несколько потоков для выполнения. Это может привести к тому, что два или более потока получат доступ к одному и тому же полю или объекту. Синхронизация — это процесс, который позволяет выполнять все параллельные потоки в программе синхронно. Синхронизация позволяет избежать ошибок согласованности памяти, вызванных непоследовательным доступом к общей памяти.
Когда метод объявлен как синхронизированный — нить держит монитор для объекта, метод которого исполняется. Если другой поток выполняет синхронизированный метод, ваш поток заблокируется до тех пор, пока другой поток не отпустит монитор.
Синхронизация достигается в Java использованием зарезервированного слова synchronized. Вы можете использовать его в своих классах определяя синхронизированные методы или блоки. Вы не сможете использовать synchronized в переменных или атрибутах в определении класса.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Как взаимодействуют программы, процессы и потоки?

A

Чаще всего одна программа состоит из одного процесса, но бывают и исключения (например, браузер Chrome создает отдельный процесс для каждой вкладки, что дает ему некоторые преимущества, вроде независимости вкладок друг от друга). В каждом процессе может быть создано множество потоков. Процессы разделены между собой (>программы), потоки в одном процессе могут взаимодействовать друг с другом (методы wait, notify, join и т.д.).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

. В каких случаях целесообразно создавать несколько потоков?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Что может произойти если два потока будут выполнять один и тот же код в программе?

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Что вы знаете о главном потоке программы?

A

Маленькие программы на Java обычно состоят из одной нити, называемой «главной нитью» (main thread). Но программы побольше часто запускают дополнительные нити, их еще называют «дочерними нитями». Главная нить выполняет метод main и завершается. Аналогом такого метода main, для дочерних нитей служит метод run интерфейса Runnable. Много потоков — много методов main (run()).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Какие есть способы создания и запуска потоков?

A

С помощью класса, реализующего Runnable
С помощью класса, расширяющего Thread
С помощью класса, реализующего java.util.concurrent.Callable

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Какой метод запускает поток на выполнение?

A

Thread.start() запускает дочерний поток. Для интерфейса Callable запуск потока осуществляется с помощью метода submit().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

в Каком методе потока описывается код для выполнения ?

A

Метод run() или метод call() для дочерних потоков. Метод main() для главного потока.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Когда поток завершает свое выполнение?

A

Поток закончит выполнение, когда завершится его метод run() или call(). Для главного потока это метод main().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Как синхронизировать метод?

A

Или указать в сигнатуре модификатор synchronized или использовать конструкцию synchronized {} внутри метода.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Как принудительно остановить поток?

A

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

Класс Thread содержит в себе скрытое булево поле, которое называется флагом прерывания. Установить этот флаг можно вызвав метод interrupt() потока. Проверить же, установлен ли этот флаг, можно двумя способами. Первый способ — вызвать метод bool isInterrupted() объекта потока, второй — вызвать статический метод bool Thread.interrupted(). Первый метод возвращает состояние флага прерывания и оставляет этот флаг нетронутым. Второй метод возвращает состояние флага и сбрасывает его. Заметьте что Thread.interrupted() — статический метод класса Thread, и его вызов возвращает значение флага прерывания того потока, из которого он был вызван. Поэтому этот метод вызывается только изнутри потока и позволяет потоку проверить своё состояние прерывания.

У методов, приостанавливающих выполнение потока, таких как sleep(), wait() и join() есть одна особенность — если во время их выполнения будет вызван метод interrupt() этого потока, они, не дожидаясь конца времени ожидания, сгенерируют исключение InterruptedException.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

поток-демон”.

A

Потоками-демонами называются потоки, работающие в фоновом режиме для нашей программы.

В Java процесс завершается тогда, когда завершается последний его поток. Даже если метод main() уже завершился, но еще выполняются порожденные им потоки, система будет ждать их завершения.
Однако это правило не относится к особому виду потоков – демонам. Если завершился последний обычный поток процесса, и остались только потоки-демоны, то они будут принудительно завершены и выполнение процесса закончится. Чаще всего потоки-демоны используются для выполнения фоновых задач, обслуживающих процесс в течение его жизни.

Thread thread = new Thread(new DaemonClass());
thread.setDaemon(true);
System.out.println(thread.isDaemon()); //true
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Как получить текущий поток?

A

Thread.currentThread(),

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

монитор

A

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

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

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

Когда одна нить заходит внутрь блока кода, помеченного словом synchronized, то Java-машина тут же блокирует мьютекс у объекта, который указан в круглых скобках после слова synchronized. Больше ни одна нить не сможет зайти в этот блок, пока наша нить его не покинет. Как только наша нить выйдет из блока, помеченного synchronized, то мьютекс тут же автоматически разблокируется и будет свободен для захвата другой нитью. Если же мьютекс был занят, то наша нить будет стоять на месте и ждать когда он освободится.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

приостановить выполнение потока?

A

Thread.sleep()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

. В каких состояниях может пребывать поток?

A

Поток может быть в следующем состоянии: созданный, запущенный, блокированный, остановленный, в режиме ожидания, в режиме ожидания по времени (NEW, RUNNABLE, BLOCKED, TERMINATED, WAITING, TIMED_WAITING).

19
Q

Что является монитором при вызове нестатического и статического метода?

A

Для нестатического метода — текущий объект this. Для статического метода — объекта типа Class, соответствующий классу, в котором определен этот метод.

20
Q

Что является монитором при выполнении участка кода метода?

A
Монитором является объект, указанный в блоке synchronized участка кода:
synchronized (synchedList) {
...
                synchedList.wait();
...
        }
21
Q

Какие методы позволяют синхронизировать выполнение потоков?

A

К этим методам относятся notify(), notifyAll(), wait(режим ожидания); Метод notify пробуждает один из потоков, который вызвал метод wait() у этого монитора. Метод notifyAll пробуждает все потоки.

22
Q

join

A

Одна нить (поток) может вызвать метод join() у другой нити. В результате первый поток (который вызвал метод) приостанавливает свою работу и ждет окончания работы второго потока (у объекта которого был вызван метод join()).
threadExample.join();

23
Q

условия вызова метода wait/notify?

A

Методы должны вызываться на объекте-мониторе только из синхронизированного кода. Поток, который вызывает эти методы должен владеть монитором, иначе будет выдано исключение java.lang.IllegalMonitorStateException.

24
Q

взаимная блокировка”.

A

Deadlock, он же взаимная блокировка, явление при котором все потоки находятся в режиме ожидания. Чтобы уменьшить шанс появления deadlock’a не рекомендуется использовать методы wait() и notify().

25
Q

Чем отличаются методы interrupt, interrupted, isInterrupted?

A

Метод interrupt() — устанавливает флаг прерывания потока.
Метод bool isInterrupted() объекта потока возвращает состояние флага прерывания и оставляет этот флаг нетронутым.
Статический метод bool Thread.interrupted() — возвращает состояние флага и сбрасывает его.

26
Q

В каком случае будет выброшено исключение InterruptedException, какие методы могут его выбросить?

A

Методы, требующие обработку этого исключения: wait, sleep, join. Исключение будет выброшено, если флаг interrupt у потока true.

27
Q

. Модификаторы volatile и метод yield()

A

Помещение модификатора volatile перед определением переменной заставляет принудительно всегда читать и писать значение только в обычную (медленную) память (а не кэшировать). Записывается как: private volatile boolean varName;

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

28
Q

Что есть в пакете java.util.concurrent

A

Concurrent Collections — набор коллекций,Queues — неблокирующие и блокирующие очереди с поддержкой многопоточности. Synchronizers — вспомогательные утилиты для синхронизации потоков, мощное оружие в «параллельных» вычислениях. Executors — содержит в себе отличные фрейморки для создания пулов потоков. Locks — представляет собой альтернативные и более гибкие механизмы синхронизации потоков Atomics — классы с поддержкой атомарных операций над примитивами и ссылками.

29
Q

Concurrent Collections

A

CopyOnWriteArrayList-Потокобезопасный аналог ArrayList
CopyOnWriteArraySet
ConcurrentMap
ConcurrentHashMap - данные представлены в виде сегментов, разбитых по hash’ам ключей. В результате, для доступ к данным лочится по сегментам, а не по одному объекту. В дополнение, итераторы представляют данные на определенный срез времени и не кидают ConcurrentModificationException.
ConcurrentSkipListMap Является аналогом TreeMap с поддержкой многопоточности.
ConcurrentSkipListSet

30
Q

Blocking Queues

A

BlockingQueue При обработке больших потоков данных через очереди становится явно недостаточно использования ConcurrentLinkedQueue. Если потоки, разгребающие очередь перестанут справляться с наплывом данных, то можно довольно быстро схлопотать out of memory или перегрузить IO/Net настолько, что производительность упадет в разы пока не настанет отказ системы по таймаутам или из за отсутствия свободных дескрипторов в системе. Для таких случаев нужна queue с возможностью задать размер очереди или с блокировками по условиям. Тут то и появляется интерфейс BlockingQueue, открывающий дорогу к целому набору полезных классов. Помимо возможности задавать размер queue, добавились новые методы, которые реагируют по-разному на незаполнение или переполнение queue. Так, например, при добавлении элемента в переполненную queue, один метод кинет IllegalStateException, другой вернет false, третий заблокирует поток, пока не появится место, четвертый же заблокирует поток с таймаутом и вернет false, если место так и не появится. Также стоит отметить, что блокирующие очереди не поддерживают null значения, т.к. это значение используется в методе poll как индикатор таймаута.

ArrayBlockingQueue Класс блокирующей очереди, построенный на классическом кольцевом буфере. Помимо размера очереди, доступна возможность управлять «честностью» блокировок. Если fair=false (по умолчанию), то очередность работы потоков не гарантируется. Более подробно о «честности» можно посмотреть в описании ReentrantLock’a.

LinkedBlockingQueue Блокирующая очередь на связанных нодах, реализованная на «two lock queue» алгоритме: один лок на добавление, другой на вытаскивание элемента. За счет двух локов, по сравнению с ArrayBlockingQueue, данный класс показывает более высокую производительность, но и расход памяти у него выше. Размер очереди задается через конструктор и по умолчанию равен Integer.MAX_VALUE.

31
Q

Synchronizers

A

Semaphore Семафоры чаще всего используются для ограничения количества потоков при работе с аппаратными ресурсами или файловой системой. Доступ к общему ресурсу управляется с помощью счетчика. Если он больше нуля, то доступ разрешается, а значение счетчика уменьшается. Если счетчик равен нулю, то текущий поток блокируется, пока другой поток не освободит ресурс. Количество разрешений и «честность» освобождения потоков задается через конструктор.

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

CyclicBarrier Может использоваться для синхронизации заданного количества потоков в одной точке. Барьер достигается когда N-потоков вызовут метод await(…) и заблокируются. После чего счетчик сбрасывается в исходное значение, а ожидающие потоки освобождаются.

Exchangerобмен объектами между двумя потоками. При этом, также поддерживаются null значения, что позволяет использовать данный класс для передачи только одного объекта или же просто как синхронизатор двух потоков. Первый поток, который вызывает метод exchange(…) заблокируется до тех пор, пока тот же метод не вызовет второй поток. Как только это произойдет, потоки обменяются значениями и продолжат свою работу.

Phaser Улучшенная реализация барьера для синхронизации потоков, которая совмещает в себе функционал CyclicBarrier и CountDownLatch, вбирая в себя самое лучшее из них. Так, количество потоков жестко не задано и может динамически меняться. Класс может повторно переиспользоваться и сообщать о готовности потока без его блокировки

32
Q

Executors

A

Future нтерфейс для получения результатов работы асинхронной операции. Ключевым методом здесь является метод get, который блокирует текущий поток (с таймаутом или без) до завершения работы асинхронной операции в другом потоке.

RunnableFutureиспользуется для запуска асинхронной части. Успешное завершение метода run() завершает асинхронную операцию и позволяет вытаскивать результаты через метод get.

CallableРасширенный аналог интерфейса Runnable для асинхронных операций Позволяет возвращать типизированное значение и кидать checked exception

FutureTaskИмплементация интерфейса Future/RunnableFuture. Асинхронная операция принимается на вход одного из конструкторов в виде Runnable или Callable объектов. Сам же класс FutureTask предназначен для запуска в worker потоке, например через new Thread(task).start(), или через ThreadPoolExecutor. Результаты работы асинхронной операции вытаскиваются через метод get(…).

Delayed Используется для асинхронных задач, которые должны начаться в будущем,
____________________________________
Executor интерфейс для классов, реализующих запуск Runnable задач.

ExecutorService Интерфейс, который описывает сервис для запуска Runnable или Callable задач. Методы submit на вход принимают задачу в виде Callable или Runnable, а в качестве возвращаемого значения идет Future, через который можно получить результат.

ScheduledExecutorService В дополнении к методам ExecutorService, данный интерфейс добавляет возможность запускать отложенные задачи.

ThreadPoolExecutor Используется для запуска асинхронных задач в пуле потоков. Тем самым практически полностью отсутствует оверхэд на поднятие и остановку потоков. А за счет фиксируемого максимума потоков в пуле обеспечивается прогнозируемая производительность приложения.

ScheduledThreadPoolExecutor В дополнении к методам ThreadPoolExecutor, позволяет запускать задачи после определенной задержки, а также с некоторой периодичностью, что позволяет реализовать на базе этого класса Timer Service.
_______________________________
Executors Класс-фабрика для создания ThreadPoolExecutor, ScheduledThreadPoolExecutor

ThreadFactory ThreadPoolExecutor использует стандартную фабрику потоков, получаемую через Executors.defaultThreadFactory(). Если нужно что-то больше, например задание приоритета или имени потока, то можно создать класс с реализацией этого интерфейса и передать его в ThreadPoolExecutor.

RejectedExecutionHandler Позволяет определить обработчик для задач, которые по каким то причинам не могут быть выполнены через ThreadPoolExecutor. Такой случай может произойти, когда нет свободных потоков или сервис выключается или выключен (shutdown). Несколько стандартных имплементаций находятся в классе ThreadPoolExecutor: CallerRunsPolicy — запускает задачу в вызывающем потоке; AbortPolicy — кидает эксцепшен; DiscardPolicy — игнорирует задачу; DiscardOldestPolicy — удаляет самую старую незапущенную задачу из очереди, затем пытается добавить новую задачу еще раз.
______________________________________
Fork Join фреймворк для решения рекурсивных задач, работающих по алгоритмам разделяй и влавствуй - с ним не работал
_______________________________________
CompletionService Интерфейс сервиса с развязкой запуска асинхронных задач и получением результатов. Так, для добавления задач используются методы submit, а для вытаскивания результатов завершенных задач используются блокирующий метод take и неблокирующий poll.

ExecutorCompletionService По сути является враппером над любым классом, реализующим интерфейс Executor, например ThreadPoolExecutor или ForkJoinPool. Используется преимущественно тогда, когда хочется абстрагироваться от способа запуска задач и контроля за их исполнением. Если есть завершенные задачи — вытаскиваем их, если нет — ждем в take пока что-нибудь не завершится. В основе сервиса по умолчанию используется LinkedBlockingQueue, но может быть передана и любая другая имплементация BlockingQueue.
_____________________________________
Condition Интерфейс, который описывает альтернативные методы стандарным wait/notify/notifyAll. Объект с условием чаще всего получается из локов через метод lock.newCondition(). Тем самым можно получить несколько комплектов wait/notify для одного объекта.

Lock азовый интерфейс из lock framework, предоставляющий более гибкий подход по ограничению доступа к ресурсам/блокам нежели при использовании synchronized. Так, при использовании нескольких локов, порядок их освобождения может быть произвольный. Плюс имеется возможность пойти по альтернативному сценарию, если лок уже кем то захвачен.

ReentrantLock Лок на вхождение. Только один поток может зайти в защищенный блок. Класс поддерживает «честную» (fair) и «нечестную» (non-fair) разблокировку потоков. При «честной» разблокировке соблюдается порядок освобождения потоков, вызывающих lock(). При «нечестной» разблокировке порядок освобождения потоков не гарантируется, но, как бонус, такая разблокировка работает быстрее. По умолчанию, используется «нечестная» разблокировка.

ReadWriteLock Дополнительный интерфейс для создания read/write локов. Такие локи необычайно полезны, когда в системе много операций чтения и мало операций записи.

ReentrantReadWriteLock Очень часто используется в многопоточных сервисах и кешах, показывая очень хороший прирост производительности по сравнению с блоками synchronized. По сути, класс работает в 2-х взаимоисключающих режимах: много reader’ов читают данные в параллель и когда только 1 writer пишет данные.

ReentrantReadWriteLock.ReadLock -Read lock для reader’ов, получаемый через readWriteLock.readLock().

ReentrantReadWriteLock.WriteLock Write lock для writer’ов, получаемый через readWriteLock.writeLock().

LockSupport Предназначен для построения классов с локами. Содержит методы для парковки потоков вместо устаревших методов Thread.suspend() и Thread.resume().

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

AbstractQueuedSynchronizer Используется в качестве базового класса для механизма синхронизации в FutureTask, CountDownLatch, Semaphore, ReentrantLock, ReentrantReadWriteLock. Может применяться при создании новых механизмов синхронизации, полагающихся на одиночное и атомарное значение int.

AbstractQueuedLongSynchronizer Разновидность AbstractQueuedSynchronizer, которая поддерживает атомарное значение long.
____________________________
Atomicsесли в классе нужно синхронизировать доступ к одной простой переменной типа int? Можно использовать конструкции с synchronized, а при использовании атомарных операций set/get, подойдет также и volatile. Но можно поступить еще лучше, использовав новые классы Atomic*. За счет использования CAS, операции с этими классами работают быстрее, чем если синхронизироваться через synchronized/volatile. Плюс существуют методы для атомарного добавления на заданную величину, а также инкремент/декремент. но не работал…

33
Q

Есть некоторый метод, который исполняет операцию i++. Переменная i типа int. Предполагается, что код будет исполнятся в многопоточной среде. Следует ли синхронизировать блок?

A

Да, иначе будет состояние гонки (race condition).

34
Q

Что используется в качестве mutex, если метод объявлен static synchronized? Можно ли создавать новые экземпляры класса, пока выполняется static synchronized метод?

A

Да, можно создать новый экземпляр класса, пока его static synchronized метод выполняется. Мои рассуждения: статик методы классов создаются в единственном экземпляре во время загрузки класса класслоадером и принадлежат объекту Class.MyClass. Во время выполнения в потоке static synchronized метода захватывается блокировка именно этого объекта. Следовательно нам ни что не мешает создать новый экземпляр класса. Загрузчиков может быть несколько, соответственно, экземпляров Class — тоже несколько, по одному на загрузчик. Создавать новые инстанции ничего не мешает, т.к. это типа выделение машиной памяти под объект и вызов метода , который не synchronized.

35
Q

Предположим в методе run возник RuntimeException, который не был пойман. Что случится с потоком? Есть ли способ узнать о том, что Exception произошел (не заключая все тело run в блок try-catch)? Есть ли способ восстановить работу потока после того как это произошло?

A

Если в дочернем потоке упадет Exception, то метод run() аварийно завершится и исключение будет передано в главный поток.Если исключение не обрабатывать, то нить (вызванная в методе run()) просто аварийно завершится. Восстановить работу нити после такого сценария нельзя, можно только создать нить заново.

36
Q

Какие стандартные инструменты Java вы бы использовали для реализации пула потоков?

A

Executors

37
Q

ThreadGroup

A

ThreadGroup представляет собой набор нитей, которые так же могут содержать в себе другие группы потоков. Группа нитей образует дерево, в котором каждая другая группа нитей имеет родителя (кроме исходной). Поток имеет право доступа к данным из своей группы нитей, но не имеет такого доступа к другим группам или к родительской группе потоков.

38
Q

ThreadPool

A

Пулы потоков (нитей) представляют собой управляемую коллекцию потоков, которые доступны для выполнения различных задач. Пулы нитей, как правило, обеспечивают:

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

39
Q

.Что такое ThreadPoolExecutor и зачем он нужен?

A

ThreadPoolExecutor — реализация ExecutorService. Он выполняет переданную задачу (Callable или Runnable), используя одну из внутренних доступных нитей из пула. Пул потоков содержит в себе ThreadPoolExecutor, который может содержать изменяющееся число нитей. Число нитей в пуле задается с помощью corePoolSize и maximumPoolSize.

40
Q

атомарные типы» в Java?

A

се атомарные классы переменных имеют базовый элемент Сравнение и назначение (compare-and-set) (аналогичный элементу Сравнение и замена), который реализуется при помощи самого быстрого собственного структурного компонента, который имеется в платформе (Сравнение и замена, Загрузить в связке, Сохранить при условии или в крайнем случае спин-блокировками). В пакет java.util.concurrent.atomic входят 9 видов атомарных переменных (AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean; формы для массивов атомарных целых чисел; длинные (long); ссылки; а также атомарные с пометкой Класс эталона (reference), которые атомарно обновляют две величины).
Классы атомарных переменных можно рассматривать как обобщение volatile переменных, если расширить понятие изменяемых переменных до переменных с поддержкой атомарных обновлений методом Сравнение и назначение. Чтение и запись атомарных переменных имеет такую же семантику памяти как доступ к чтению и записи изменяемых переменных.Переменные current и next — локальные, а следовательно у каждого потока свои экземпляры этих переменных. Следует обратить внимание лишь на разделяемое состояние, т.е. переменную value. Т.к. переменная value объявлена с модификатором volatile, то гарантируется выполнение отношения happens-before, что ведет к тому, что измененное значение этой переменной увидят все потоки.

Метод compareAndSet представляет из себя механизм оптимистичной блокировки и позволяет изменить значение value, только если оно равно ожидаемому значению (т.е. current).

Если же значение value было изменено в другом потоке, то оно не будет равно ожидаемому значению. Следовательно метод compareAndSet вернет значение false, что приведет к новой итерации цикла while в методе getAndAdd. Т.е. новое значение value будет перезачитано в переменную current, после чего будет произведено сложение и новая попытка записи получившегося значения (т.е. next).

41
Q

ThreadLocal

A

ThreadLocal предоставляет абстракцию над переменными локальными по отношению к потоку исполнения java.lang.Thread. ThreadLocal переменные отличаются от обычных переменных тем, что у каждого потока свой собственный, индивидуально инициализируемый экземпляр переменной, доступ к которой он получает через методы get() или set(). У каждого потока — т.е. экземпляра класса Thread — есть ассоциированная с ним таблица ThreadLocal-переменных. Ключами таблицы являются cсылки на объекты класса ThreadLocal, а значениями — ссылки на объекты, «захваченные» ThreadLocal-переменными.

42
Q

Executor

A
Executor — интерфейс, который может выполнять подтвержденные задачи. Интерфейс предоставляет возможность избежать вникания в механику выполнения задачи и деталей использования выполняемого потока. Executor обычно используется для явного создания нитей. Например так:
//Вместо
Thread(new(RunnableTask())).start():
//Лучше использовать
Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
43
Q

ExecutorService

A

ExecutorService исполняет асинхронный код в одном или нескольких потоках. Создание инстанса ExecutorService’а делается либо вручную через конкретные имплементации (ScheduledThreadPoolExecutor или ThreadPoolExecutor), но проще будет использовать фабрики класса Executors. Например, если надо создать пул с 2мя потоками, то делается это так:

ExecutorService service = Executors.newFixedThreadPool(2);
Если требуется использовать кэширующий пул потоков, который создает потоки по мере необходимости, но переиспользует неактивные потоки (и подчищает потоки, которые были неактивные некоторое время), то это задается следующим образом:
ExecutorService service = Executors.newCachedThreadPool();
Если требуется запустить асинхронный код несколько раз, то это будет выполняться так:
ExecutorService service = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++) {
 service.submit(new Runnable() {
  public void run() {
   // snip... piece of code
  }
 });

Метод submit также возвращает объект Future, который содержит информацию о статусе исполнения переданного Runnable или Callable (который может возвращать значение). Из него можно узнать выполнился ли переданный код успешно, или он еще выполняется. Вызов метода get на объекте Future возвратит значение, который возвращает Callable (или null, если используется Runnable). Метод имеет 2 checked-исключения: InterruptedException, который бросается, когда выполнение прервано через метод interrupt(), или ExecutionException если код в Runnable или Callable бросил RuntimeException, что решает проблему поддержки исключений между потоками.

44
Q

ScheduledExecutorService

A

Иногда требуется выполнение кода асихронно и периодически или требуется выполнить код через некоторое время, тогда на помощь приходит ScheduledExecutorService. Он позволяет поставить код выполняться в одном или нескольких потоках и сконфигурировать интервал или время, на которое выполненение будет отложено. Интервалом может быть время между двумя последовательными запусками или время между окончанием одного выполнения и началом другого. Методы ScheduledExecutorService возвращают ScheduledFuture, который также содержит значение отсрочки для выполнения ScheduledFuture.