Проект

Общее

Профиль

MULTITHREADING » История » Версия 2

Александр Александров, 21.04.2019 16:43

1 1 Александр Александров
h1. MULTITHREADING
2
3
h2. Вопросы
4
5
# Чем отличается процесс от потока?
6
# Каким образом можно создать поток?
7
# Что такое монитор?
8
# Какие способы синхронизации в Java?
9
# Как работают методы wait и notify/notifyAll?
10
# Чем отличается работа метода wait с параметром и без параметра?
11
# Как работает метод Thread.yield()? Чем отличаются методы Thread.sleep() и Thread.yield()?
12
# Как работает метод Thread.join()?
13
# Что такое dead lock?
14
# На каком объекте происходит синхронизация при вызове static synchronized метода?
15
# Для чего используется ключевое слово volatile, synchronized, transient, native?
16
# Что значит приоритет потока?
17
# Что такое потоки – демоны в java?
18
# Что значит усыпить поток?
19
# В каких состояниях может быть поток в джава? Как вообще работает поток?
20
# Чем отличаются два интерфейса для реализации задач Runnable и Callable?
21
# Различия между CyclicBarrier и CountDownLatch?
22
# Что такое состояние гонки (race condition)?
23
# Как остановить нить?
24
# Что происходит, когда в нити появляется исключение?
25
# Что такое ThreadLocal переменная?
26
# Что такое FutureTask?
27
# Различие между interrupted и isInterrupted?
28
# Почему методы wait и notify вызываются в синхронизированном блоке?
29
# Что такое пул нитей?
30
# Различия между livelock и deadlock?
31
# Как проверить, удерживает ли нить lock?
32
# Как получить дамп нити?
33
# Какой JVM параметр используется для контроля размера стека нити?
34
# Различия между synchronized и ReentrantLock?
35
# Что такое Semaphore?
36
# Что будет, если очередь пула нитей уже заполнена, а вы подадите задачу?
37
# Различия между методами submit() и execute() у пула нитей?
38
# Что такое блокирующий метод?
39
# Что такое ReadWriteLock?
40
# Что такое double checked locking Синглтона?
41
# Что такое фреймворк Fork/Join?
42
43
h2. Ответы
44
45
h3. Чем отличается процесс от потока?
46
47 2 Александр Александров
Процесс это некоторая единица операционной системы, которой выделена память и другие ресурсы. Поток это единица исполнения кода. Поток имеет стэк - некоторую свою память для исполнения. Остальная память процесса - общая для всех его потоков. Потоки исполняются на ядрах процессора. В некоторых OS разница между процессами и потоками сведена к минимуму.
48
49 1 Александр Александров
h3. Каким образом можно создать поток?
50
51 2 Александр Александров
Есть несколько способов создания и запуска потоков:
52
* С помощью класса, реализующего Runnable:
53
** Создать объект класса Thread.
54
** Создать объект класса, реализующего интерфейс Runnable.
55
** Вызвать у созданного объекта Thread метод start() (после этого запустится метод run() у переданного объекта, реализующего Runnable).
56
* С помощью класса, расширяющего Thread:
57
** Создать объект класса ClassName extends Thread.
58
** Переопределить run() в этом классе (смотрите примере ниже, где передается имя потока 'Second')
59
* С помощью класса, реализующего java.util.concurrent.Callable:
60
** Создать объект класса, реализующего интерфейс Callable.
61
** Создать объект ExecutorService с указанием пула потоков.
62
** Создать объект Future. Запуск происходит через метод submit(); Сигнатура: <T> Future<T> submit(Callable<T> task).
63
64 1 Александр Александров
h3. Что такое монитор?
65
66 2 Александр Александров
Контроль за доступом к объекту-ресурсу обеспечивает понятие монитора. Монитор экземпляра может иметь только одного владельца. При попытке конкурирующего доступа к объекту, чей монитор имеет владельца, желающий заблокировать объект-ресурс поток должен подождать освобождения монитора этого объекта и только после этого завладеть им и начать использование объекта-ресурса.
67
68 1 Александр Александров
h3. Какие способы синхронизации в Java?
69
70 2 Александр Александров
Ниже приведены некоторые способы синхронизации в Java:
71
* Системная синхронизация с использованием wait/notify. Поток, который ждет выполнения каких-либо условий, вызывает у этого объекта метод wait, предварительно захватив его монитор. На этом его работа приостанавливается. Другой поток может вызвать на этом же самом объекте метод notify (опять же, предварительно захватив монитор объекта), в результате чего, ждущий на объекте поток "просыпается" и продолжает свое выполнение.
72
* Системная синхронизация с использованием join. Метод join, вызванный у экземпляра класса Thread, позволяет текущему потоку остановиться до того момента, как поток, связаный с этим экземпляром, закончит работу.
73
* Использование классов из пакета java.util.concurrent, который предоставляет набор классов для организации межпоточного взаимодействия. Примеры таких классов - Lock, семафор (Semaphore), etc. Концепция данного подхода заключается в использовании атомарных операций и переменных.
74
75 1 Александр Александров
h3. Как работают методы wait и notify/notifyAll?
76
77 2 Александр Александров
Эти метеоды предназначены для межпоточной синхронизации, для взаимодействия потоков между собой. Как работают эти методы. Во-первых они могут вызваны только потоком, который захватил монитор объекта, для которого эти методы вызываются. То есть они вызываются внутри блока synchronized и для объекта, монитор которого этим synchronized захвачен. Если внутри synchronized метода - то для класса, к которому относятся эти методы.
78
79
Что делает метод wait(). Метод wait() отдает (освобождает) монитор объекта, так что другие потоки теперь могут его (монитор) захватить, то есть войти в блок synchronized для этого объекта. Затем метод wait() переходит в
80
состояние ожидания, до тех пор пока другой поток не вызывет метод notify() или notifyAll() для этого же объекта. После чего поток, в котором был вызван wait(), пытается снова захватить монитор объекта и когда монитор становится свободным, то есть когда другой поток освобождает его, захватывает монитор и продолжает выполнение со следующего после wait() оператора. Причем у потока вызвашего wait() нет никакого преимущества
81
перед другими потоками, ожидающими захвата того же монитора.
82
83
Что делают методы notify(), notifyAll(). Они "пробуждают" поток, ожидающий методом wait() (если такой есть), и переводят его в состояние ожидания освобождения монитора. Разница между notify() и notifyAll() в том, что notify() пробуждает только один поток , ожидающий методом wait(), какой именно будет пробужден - определить нельзя, а notifyAll() - все такие потоки.
84
85 1 Александр Александров
h3. Чем отличается работа метода wait с параметром и без параметра?
86
87 2 Александр Александров
Разница методов в следующем:
88
89
* *final void wait()* - метод используется в многопоточной среде, может вызываться только потоком, владеющим объектом синхронизации. При этом объект синхронизации освобождается, а текущий поток переходит в режим ожидания сигнала освобождения объекта синхронизации другим потоком путем вызова метода notify() либо notifyAll().
90
* *final void wait(long time)* - аналогично wait() данный метод используется в многопоточной среде, переходит текущий поток в режим ожидания сигнала освобождения объекта синхронизации другим потоком путем вызова метода notify() либо notifyAll(), или ожидание происходит заданное время time, затем выполнение продолжается безусловно.
91
92 1 Александр Александров
h3. Как работает метод Thread.yield()? Чем отличаются методы Thread.sleep() и Thread.yield()?
93
94 2 Александр Александров
Основные отличия:
95
96
* метод *yield()* - пытается сказать планировщику потоков, что нужно выполнить другой поток, что ожидает в очереди на выполнение. Метод не пытается перевести текущий поток в состояние блокировки, сна или ожидания. Он просто пытается его перевести из состояние "работающий" в состояние "работоспособный". Однако выполнение метода может вообще не произвести никакого эффекта. состояние потока остатается RUNNABLE.
97
* метод *sleep()* - приостанавливает поток на указанное. состояние меняется на TIMED_WAITING, по истечению - RUNNABLE
98
* метод *wait()* - меняет состояние потока на WAITING может быть вызвано только у объекта владеющего блокировкой, в противном случае выкинется исключение IllegalMonitorStateException. при срабатывании метода блокировка отпускается, что позволяет продолжить работу другим потокам ожидающим захватить ту же самую блокировку . в случае wait(int) с аргументом состояние будет TIMED_WAITING.
99
100 1 Александр Александров
h3. Как работает метод Thread.join()?
101
102 2 Александр Александров
Метод join() вызывается для того, чтобы привязать текущий поток в конец потока для которого вызывается метод. То есть второй поток будет в режиме блокировки пока первый поток не выполнится.
103
104 1 Александр Александров
h3. Что такое dead lock?
105
106 2 Александр Александров
Это когда один поток А получил блокировку на объект А1, а поток В получил блокировку на объект В1. В то время как поток А пытается получит блокировку на объект В1, а поток В на А1.
107
108 1 Александр Александров
h3. На каком объекте происходит синхронизация при вызове static synchronized метода?
109
110 2 Александр Александров
Представьте себе ситуацию что два потока одновременно изменяют состояние какого-то объекта, это недопустимо. Для этого необходимо синхронизировать потоки. Как это сделать? Ключевое слово synchronized позволяет это сделать установив в сигнатуре метода. Или же в методе можно описать блок synchronized, только в качестве параметра необходимо передать объект, который будет блокироватся.
111
112
Представьте себе ситуацию когда один поток ждет пока разблокируется объект… а если это ждут несколько потоков? Нет гарантии что тот объект что больше всех ждал снятия блокировки будет выполнятся первым. Статические синхронизированные методы и нестатические синхронизированные методы не будет блокировать друг друга, никогда. Статические методы блокируются на экземпляре класса Class в то время как нестатические методы блокируются на текущем экземпляре (this). Эти
113
действия не мешают друг другу. wait() - отказывается от блокировки остальные методы сохраняют блокировку.
114
115 1 Александр Александров
h3. Для чего используется ключевое слово volatile, synchronized, transient, native?
116
117 2 Александр Александров
Краткое описание ключевых слов:
118
119
* *volatile* - указывает на то, что поле синхронизировано для нескольких потоков.
120
* *synchronized* - указывает на то что метод синхронизированный или же в методе может находится такой блок синхронизации.
121
* *transient* - указывает на то, что переменная не подлежит сериализации.
122
* *native* - говорит о том, что реализация метода написана на другой программной платформе.
123
124 1 Александр Александров
h3. Что значит приоритет потока?
125
126 2 Александр Александров
Приоритет потока - это число от 1 до 10, в зависимости от которого, планировщик потоков выбирает какой поток запускать. Однако полагаться на приоритеты для предсказуемого выполнения многопоточной программы нельзя!
127
128 1 Александр Александров
h3. Что такое потоки – демоны в java?
129
130 2 Александр Александров
Это потоки, которое работают в фоновом режиме и не гарантируют что они завершатся. Тоеть если все потоки завершились, то поток демон просто обрывается вместе с закрытием приложения.
131
132 1 Александр Александров
h3. Что значит усыпить поток?
133
134 2 Александр Александров
Перевести поток в спящее состояние можно с помощью метода sleep(long ms) ms - время в миллисекундах. При вызове этого метода, поток переходит в спящее состояние, после сна, поток переходит в пул потоков и находится в состоянии "работоспособный", т.е. не гарантируется что после пробуждения он будет сразу выполняться. Также поток не может усыпить другой поток, так как метод sleep - это статический метод! Вы просто усыпите текущий поток и не более того! Также метод sleep() может возбуждать InterruptedException().
135 1 Александр Александров
136 2 Александр Александров
h3. В каких состояниях может быть поток в java? Как вообще работает поток?
137
138
У нас есть текущий поток, в котором выполняется метод main. Этот поток имеет свой стек и этот стек начинается с вызова метода main. Далее в методе main мы создаем новый поток, что происходит… создается новый поток и для него выделяется свой стек с первоначальным методом run().
139
140
Когда мы запускаем несколько потоков, то мы не можем гарантировать определенный порядок их вызовов. Планированием потоков занимается планировщик потоков JVM, выбирая из пулов потоков поток. Мы даже не можем гарантировать что если первый поток начался выполнятся первым, то он и закончит выполнятся первым, он может закончить выполнятся последним.
141
142
Еще такой нюанс, что поток, который закончил свое выполнение, не может быть повторно запущен! Он находится в состоянии "мертвый", а для запуска потока нового потока, объект должен находится в состоянии "новый". Потоки имеют такие состояния:
143
144
* *новый* - это когда только создали экземпляр класса Thread.
145
* *живой или работоспособный* - переходит в это состояние после запуска метода start(), но это не означает что поток уже работает! Или же он может перейти в это состояние из состояние работающий или блокированный)
146
* *работающий* - это когда метод run() начал выполнятся
147
* *ожидающий (waiting)/Заблокированный (blocked)/Спящий(sleeping)* - эти состояния характеризуют поток как не готовый к работе. Я объединил эти состояния т.к. все они имеют общую черту – поток еще жив (alive), но в настоящее время не может быть выполнен. Другими словами поток уже не работает, но он может вернутся в рабочее состояние. Поток может быть заблокирован, это может означать что он ждет освобождение каких-то ресурсов. Поток может спать, если встретился метод sleep(long s) , или же он может ожидать, если встретился метод wait(), он будет ждать пока не вызовится метод notify() или notifyall().
148
* *мертвый* - состояние когда метод run() завершил свою работу.
149
150
Диаграмма с уточнение того что выход из состояние waiting обязательно переходит только в blocked
151
152
{{dmsf_image(32)}}
153
154
Распространённая диаграмма состояний потоков в Java
155
156
{{dmsf_image(34)}}
157
158
Граф перехода состояний потоков Java
159
160
{{dmsf_image(33)}}
161
162 1 Александр Александров
h3. Чем отличаются два интерфейса для реализации задач Runnable и Callable?
163
164 2 Александр Александров
Основные различия:
165
166
* Интерфейс Runnable появиля в Java 1.0, а интерфейс Callable был введен в Java 5.0 в составе библиотеки java.util.concurrent. 
167
* Классы, реализующие интерфейс Runnable должны реализовывать метод run() для выполнения задачи. Классы, реализующие интерфейс Callable должны реализовывать метод call() для выполнения задачи.
168
* Метод Runnable.run() не возвращает никакого значения, его тип void, а метод Callable.call() может возвращать значение типа T. Интерфейс Callable является параметризированным Callable<T> и тип значения, которое будет возвращаться в методе call() задается этим параметром T.
169
* Метод run() не может бросить проверяемое исключение, в то время как метод call() может бросить проверяемое исключение.
170
171 1 Александр Александров
h3. Различия между CyclicBarrier и CountDownLatch?
172
173 2 Александр Александров
Хоть оба эти синхронизаторы позволяют нитям дожидаться друг друга, главное различие между ними в том, что вы не можете заново использовать CountDownLatch после того, как его счётчик достигнет нуля, но вы можете использовать CyclicBarrier снова, даже после того, как барьер сломается.
174
175 1 Александр Александров
h3. Что такое состояние гонки (race condition)?
176
177 2 Александр Александров
Состояние гонки - причина трудноуловимых багов. Как сказано в самом названии, состояние гонки возникает из-за гонки между несколькими нитями, если нить, которая должна исполнятся первой, проиграла гонку и исполняется вторая, поведение кода изменяется, из-за чего возникают недетерменированные баги. Это одни из сложнейших к отлавливанию и воспроизведению багов, из-за беспорядочной природы гонок между нитями. Пример состояния гонки - беспорядочное исполнение.
178
179 1 Александр Александров
h3. Как остановить нить?
180
181 2 Александр Александров
Java предоставляет богатые API для всего, но, по иронии судьбы, не предоставляет удобных способов остановки нити. В JDK 1.0 было несколько управляющих методов, например stop(), suspend() и resume(), которые были помечены как deprecated в будущих релизах из-за потенциальных угроз взаимной блокировки, с тех пор разработчики Java API не предприняли попыток представить стойкий, ните-безопасный и элегантный способ остановки нитей. Программисты в основном полагаются на факт того, что нить останавливается сама, как только заканчивает выполнять методы run() или call(). Для остановки вручную, программисты пользуются преимуществом volatile boolean переменной и проверяют её значение в каждой итерации, если в методе run() есть циклы, или прерывают нити методом interrupt() для внезапной отмены заданий.
182
183 1 Александр Александров
h3. Что происходит, когда в нити появляется исключение?
184
185 2 Александр Александров
Это один из хороших вопросов с подвохом. Простыми словами, если исключение не поймано - нить мерта, если установлен обработчик непойманных исключений, он получит колбек. Thread.UncaughtExceptionHandler – интерфейс, определённый как вложенный интерфейс для обработчиков, вызываемых, когда нить внезапно останавливается из-за непойманного исключения. Когда нить собирается остановится из-за непойманного исключения, JVM проверит её на наличие UncaughtExceptionHandler, используя Thread.getUncaughtExceptionHandler(), и вызовет у обработчика метод uncaughtException(), передав нить и исключение в виде аргументов.
186
187 1 Александр Александров
h3. Что такое ThreadLocal переменная?
188
189 2 Александр Александров
ThreadLocal переменные - специальный вид переменных, доступных Java программисту. Так же, как для состояний есть переменная состояния, для нитей есть ThreadLocal переменные. Это неплохой способ достичь нитебезопасности для затратных-для-создания объектов, например вы можете сделать SimpleDateFormat ните-безопасным, используя ThreadLocal. Так как это затратный класс, его нежелательно использовать в локальной области, которая требует отдельных экземпляров на каждый вызов. Предоставляя каждой нити её собственную копию, вы убиваете двух зайцев. Во-первых, вы уменьшаете количество экземпляров затратных объектов, используя по новой фиксированное количество экземпляров, и во-вторых, вы достигаете ните-безопасности, без потерь синхронизации и неизменяемости. Ещё один хороший пример локальной переменной у нити - класс ThreadLocalRandom, который уменьшает количество экземпляров затратных-для-создания объектов Random в много-нитиевой среде.
190
191 1 Александр Александров
h3. Что такое FutureTask?
192
193 2 Александр Александров
*FutureTask* представляет собой отменяемое асинхронное вычисление в параллельном Java приложении. Этот класс предоставляет базовую реализацию Future, с методами для запуска и остановки вычисления, методами для запроса состояния вычисления и извлечения результатов. Результат может быть получен только когда вычисление завершено, метод получения будет заблокирован, если вычисление ещё не завершено. Объекты FutureTask могут быть использованы для обёртки объектов Callable и Runnable. Так как FutureTask реализует Runnable, его можно передать Executor’у на выполнение.
194
195 1 Александр Александров
h3. Различие между interrupted и isInterrupted?
196
197 2 Александр Александров
Основное различие между interrupted() и isInterrupted() в том, что первый сбрасывает статус прерывания, а второй нет. Механизм прерывания в Java реализован с использованием внутреннего флага, известного как статус прерывания. Прерывание нити вызовом Thread.interrupt() устанавливает этот флаг. Когда прерванная нить проверяет статус прерывания, вызывая статический метод Thread.interrupted(), статус прерывания сбрасывается. Нестатический метод isInterrupted(), который используется нитью для проверки статуса прерывания у другой нити, не изменяет флаг прерывания. Условно, любой метод, который завершается, выкинув InterruptedException сбрасывает при этом флаг прерывания. Однако, всегда существует возможность того, что флаг тут же снова установится, если другая нить вызовет interrupt().
198
199 1 Александр Александров
h3. Почему методы wait и notify вызываются в синхронизированном блоке?
200
201 2 Александр Александров
Основная причина вызова wait и notify из синхронизированого блока или метода в том, что Java API обязательно требует этого. Если вы вызовете их не из синхронизированного блока, ваш код выбросит IllegalMonitorStateException. Более хитрая причина в том, чтобы избежать состояния гонки между вызовами wait и notify.
202
203 1 Александр Александров
h3. Что такое пул нитей?
204
205 2 Александр Александров
Создание нити затратно в плане времени и ресурсов. Если вы создаёте нить во время обработки запроса, это замедлит время отклика, также процесс может создать только ограниченное число нитей. Чтобы избежать этих проблем, во время запуска приложения создаётся пул нитей и нити повторно используются для обработки запросов. Этот пул нитей называется "thread pool", а нити в нём – рабочая нить. Начиная с Java 1.5 Java API предоставляет фреймворк Executor, который позволяет вам создавать различные пулы нитей, например single thread pool, который обрабатывает только одно задание за единицу времени, fixed thread pool, пул с фиксированным количеством нитей, и cached thread pool, расширяемый пул, подходящий для приложений с множеством недолгих заданий
206
207 1 Александр Александров
h3. Различия между livelock и deadlock?
208
209 2 Александр Александров
Livelock схож с deadlock, только в livelock состояния нитей или вовлечённых процессов постоянно изменяются в зависимости друг от друга. Livelock - особый случай нехватки ресурсов. Реальный пример livelock'а - когда два человека встречаются в узком коридоре и каждый, пытаясь быть вежливым, отходит в сторону, и так они бесконечно двигаются из стороны в сторону.
210
211 1 Александр Александров
h3. Как проверить, удерживает ли нить lock?
212
213 2 Александр Александров
Я и не подозревал, что можно проверять, удерживает ли нить lock в данный момент, до тех пор, пока не столкнулся с этим вопросом в одном телефонном интервью. В java.lang.Thread есть метод holdsLock(), он возвращает true, тогда и только тогда, когда текущая нить удерживает монитор у определённого объекта.
214
215 1 Александр Александров
h3. Как получить дамп нити?
216
217 2 Александр Александров
Дамп нити позволяет узнать, чем нить занимается в данный момент. Существует несколько способов получения дампа нити, зависящих от операционной системы. В Windows вы можете использовать комбинацию ctrl + Break, в Linux - команду kill -3. Также вы можете воспользоваться утилитой jstack, она оперирует над id процесса, который вы можете узнать с помощью другой утилиты jps.
218
219 1 Александр Александров
h3. Какой JVM параметр используется для контроля размера стека нити?
220
221 2 Александр Александров
Это один из простых, -Xss параметер используется для контроля размера стека нити в Java.
222
223 1 Александр Александров
h3. Различия между synchronized и ReentrantLock?
224
225 2 Александр Александров
Были времена, когда единственный способ достижения взаимного исключения был через ключевое слово synchronized, но он имеет несколько недостатков, например нельзя расширить lock за пределами метода или блока кода и т.д. Java 5 решает эту проблему, предоставляя более утончённый контроль через интерфейс Lock. ReentrantLock – распространённая реализация Lock, которая предоставляет Lock с таким же базовым поведением и семантикой, как у неявного монитора, достигаемый использованием синхронизированных методов, но с расширенными возможностями.
226
227 1 Александр Александров
h3. Что такое Semaphore?
228
229 2 Александр Александров
*Semaphore* - это новый тип синхронизатора. Это семафор со счётчиком. Концептуально, семафор управляет набором разрешений. Каждый acquire() блокируется, если необходимо, до того, как разрешение доступно, затем  получает его. Каждый release() добавляет разрешение, потенциально освобождая блокирующий получатель (acquirer). Однако при этом не используются фактические объекты разрешений; Semaphore просто хранит количество доступных и действует соответственно. Semaphore используется для защиты дорогих ресурсов, которые доступны в ограниченном количестве, например подключение к базе данных в пуле.
230
231 1 Александр Александров
h3. Что будет, если очередь пула нитей уже заполнена, а вы подадите задачу?
232
233 2 Александр Александров
Если очередь пула нитей заполнилась, то поданная задача будет "отклонена". Метод submit() у ThreadPoolExecutor'а выкидывает RejectedExecutionException, после чего вызывается RejectedExecutionHandler.
234
235 1 Александр Александров
h3. Различия между методами submit() и execute() у пула нитей?
236
237 2 Александр Александров
Оба метода являются способами подачи задачи в пул нитей, но между ними есть небольшая разница. Execute(Runnable command) определён в интерфейсе Executor и выполняет поданную задачу в будущем, но, что более важно, ничего не возвращает. С другой стороны submit() – перегруженный метод, он может принимать задачи типов Runnable и Callable и может возвращать объект Future, который можно использовать для отмены выполнения и/или ожидания результата вычислений. Этот метод определён в интерфейсе ExecutorService, который наследуется от интерфейса Executor, и каждый класс пула нитей, например ThreadPoolExecutor или ScheduledThreadPoolExecutor, наследует эти методы.
238
239 1 Александр Александров
h3. Что такое блокирующий метод?
240
241 2 Александр Александров
Блокирующий метод - метод, который блокируется, до тех пор, пока не выполнится задание, например метод accept() у ServerSocket блокируется в ожидании подключения клиента. Здесь блокирование означает, что контроль не вернётся к вызывающему методу до тех пор, пока не выполнится задание. С другой стороны, существуют асинхронные или не блокирующиеся методы, которые завершаются до выполнения задачи.
242
243 1 Александр Александров
h3. Что такое ReadWriteLock?
244
245 2 Александр Александров
В целом, *ReadWriteLock* - это результат техники разбора lock'а для улучшения производительности параллельных приложений. Это интерфейс, который был добавлен в Java 5. Он оперирует парой связанных lock’ов, один для операций чтения, один для записи. Читающий lock может удерживаться одновременно несколькими читающими нитями, до тех пор пока не будет записывающих. Записывающий lock эксклюзивен. Если хотите, вы можете реализовать интерфейс с вашим набором правил, или вы можете использовать ReentrantReadWriteLock, который поддерживает максимум 65535 рекурсивных записывающих lock'ов и 65535 читающих lock'ов.
246
247 1 Александр Александров
h3. Что такое double checked locking Синглтона?
248
249 2 Александр Александров
Это старый способ создания ните-безопасного синглтона, который пытается оптимизировать производительность, блокируясь только когда экземпляр синглтона создаётся впервые.
250
251 1 Александр Александров
h3. Что такое фреймворк Fork/Join?
252 2 Александр Александров
253
Фреймворк Fork/Join, представленный в JDK 7, - это мощная утилита, позволяющая разработчику пользоваться преимуществами нескольких процессоров у современных серверов. Он разработан для работы, которую можно рекурсивно разбить на маленькие частицы. Цель - использовать всю доступную вычислительную мощь, для увеличения производительности вашего приложения. Одного значительное преимущество этого фреймворка в том, что он использует work-stealing алгоритм (от work - работа и steal - красть). Рабочие нити, у которых закончились свои задания, могут "своровать" задания у других нитей, которые всё ещё заняты.
Go to top