14-15 Многопоточное программирования Flashcards

1
Q

Чем отличается процесс от потока?

A

Процесс — программа, выполняющаяся в текущий момент времени, и все её элементы: адресное пространство, глобальные переменные, регистры, потоки, открытые файлы и т. д.

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

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

  • процессы, как правило, независимы, а потоки существуют как составные элементы процессов;
  • процессы несут значительно больше информации о программе, а несколько потоков совместно используют эту информацию внутри процесса;
  • процессы имеют отдельные адресные пространства, а потоки совместно используют память процесса;
  • переключение между потоками в одном процессе, как правило, быстрее, чем переключение между процессами.

Многозадачность - возможность параллельно обрабатывать несколько задач. Делиться на два
типа:
1. На основе процессов - одновременное выполнение нескольких программ на компьютере:
одновременно пользоваться браузером, работать в текстовом редакторе и тд. Наименьшей
единицей, которую может диспетчеризировать планировщик операционной системы, является
программа.
2. На основе потоков - наименьшей единицей диспетчеризируемого кода является поток
исполнения. Это означает, что одна программа может выполнять несколько задач
одновременно:
что-то скачивать из сети, обработка действий пользователя и т.д..

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

Каким образом можно создать поток?

A

Способ 1:
имплементировать интерфейс Runnable.
Создать объект класса Thread, передав ему в конструкторе нечто, реализующее интерфейс Runnable.
Этот интерфейс содержит метод run(), который будет выполняться в новом потоке. Поток закончит выполнение, когда завершится его метод run().

Способ 2:
Создать наследника класса Thread и переопределить его метод run():

Если нам необходимы поля и методы Thread
- мы наследуемся, если нет, то имплементируем Runnable.

Каждый процесс имеет хотя бы один выполняющийся поток. Тот поток, с которого начинается выполнение программы, называется главным. В языке Java, после создания процесса, выполнение главного потока начинается с метода main(). Затем, по мере необходимости, в заданных программистом местах, и при выполнении заданных им же условий, запускаются другие, побочные потоки.

В языке Java поток представляется в виде объекта-потомка класса Thread. Этот класс инкапсулирует стандартные механизмы работы с потоком.

thread.start(); - запускает поток throws InterruptedException

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

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

A

С помощью метода в классе Thread.currentThread();

методы класса Thread

activeCount() - Текущее количество активных потоков в группе, к которой принадлежит поток
checkAccesss() -Текущему потоку разрешается изменять объект Thread
countStackFrames() - Определение количества фреймов в стеке
Thread currentThread() - Определение текущего работающего потока
getName() Получает имя потока
getPriority() Получается приоритет потока
setPriority(int priority) Устанавливает приоритет потока
isAlive() Определяет, выполняется ли поток
join() Заставляет родительский поток ожидать выполнения текущего
run() Точка входа в поток, основной метод с кодом
sleep(long millis) Приостанавливает выполнение на определенное время
start() Запускает поток, вызывая метод run()
setDaemon(boolean isDaemon) Отметить поток как “не важный” или “важный”.
interrupt() Прерывает выполнение потока
isInterrupted() Возвращает значение флага isInterrupted - был ли вызван
interrupt у данного потока

isAlive() Возвращает true, если поток уже был запущен, и еще в процессе

выполнения своей задачи.

isDaemon() Возвращает true, если поток является “демоном” — не важным

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

Что делают методы isAlive и join?

A

public final void join() throws InterruptedException
Метод join() присоединение к родительскому потоку, родительский поток завершится только после выполнения задачи дочернего потока.

Этот метод ожидает завершения того потока исполнения, для которого он вызван. Вызывающий поток ожидает, когда указанный поток присоединится к нему.

Метод join() имеет перегруженные методы, которые получают в качестве параметра время ожидания. В этом случае join() возвращает управление либо когда завершится ожидаемый поток, либо когда закончится время ожидания. Подобно методу Thread.sleep() метод join может ждать в течение миллисекунд и наносекунд – аргументы те же.
public final synchronized void join(long millis) throws InterruptedException
public final synchronized void join(long millis, int nanos) throws InterruptedException

Необходимое условие работы метода join() - обернуть в конструкцию try-catch. Вызывающий их код должен перехватывать исключение InterruptedException, которое они бросают при прерывании во время ожидания.

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

Какие способы синхронизации существуют в java?

A

synchronized
1) Синхронизация на уровне метода(монитором является объект):

У объекта могут быть методы, которые подразумевают использование только одним
потоком за один раз, тогда как использование других методов может быть доступно
для нескольких потоков одновременно.
public synchronized void method()
В этом случае этот метод будет выполняться только одним потоком одновременно у
объекта, который они разделяют между собой.

“проверить текущее количество монет в сундуке может только один
поток за раз, остальные будут ждать, пока первый поток освободит метод объекта и
соответственно, действовать будут по очереди.”

2) Синхронизация по классу (монитором является объект класса класс):
ключевое слово synchronized используется в статическом методе класса, что позволяет использовать этот метод, принадлежащий всему классу только одним потоком за один раз.

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

Синхронизация - это процесс (механизм), который обеспечивает, что доступ к ресурсу (объект, методы и тп) будет доступен только одному потоку одновременно.

В Java используется понятие монитор. Если один поток захватил монитор, все остальные потоки, ждут,
пока монитор освободится (состояние BLOCKED).

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

Синхронизация происходит в рамках монитора

Атомарные операции:
тип AtomicInteger
метод incrementAndGet

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

Что такое монитор?

A

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

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

Объект:
Object object = new Object();
synchronized (object) {
}
Метод объекта (в данном случае монитором будет объект, у которого вызывается метод inc):
synchronized void inc() {
 state++;
}
Статический метод (в данном случае монитором будет класс статического метода NoSyncIncrementThread.class):
synchronized static void inc() {
 state++;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Расскажите про методы работы с ключевым словом synchronized?

A

Для использования синхронизации
предусмотрено ключевое слово synchronized
Мы можем использовать synchronized как целиком на метод или если нет необходимости,
синхронизировать весь метод, применить только на блок кода

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

Для чего используется ключевое слово volatile?

A
  • Volatile обычно используют для установки флагов для потоков - когда ему завершаться или наоборот продолжать работу.
  • ключевое слово volatile необходимо использовать для переменных, которые используются разными потоками.
  • ключевое слово volatile говорит нам что значение нужно читать из оперативной памяти.
  • Volatile не заменяет синхронизацию (оно про работу с памятью).

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

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

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

Как работают методы wait, notify, notifyAll из класса Object?

A

public final void wait() throws InterruptedException: (вызывается у объектов )
Вызывающий поток уступает монитор и переходит в состояние ожидание (WAITING) до тех пор, пока какой-нибудь другой поток не возьмет тот же монитор и не вызовет метод
notify()/notifyAll()

public final native void notify();
notify(): продолжает работу потока в рамках одного монитора, у которого ранее был вызван метод wait()
Т.е. поток выходит из состояние WAITING и пытается взять монитор, если получается, то переходит в состояние RUNNABLE, иначе - BLOCKED (пытается захватить монитор)

public final native void notifyAll();
notifyAll(): возобновляет работу всех потоков, у которых ранее был вызван метод wait()

Все эти методы объявлены в классе Object, что означает, что методы доступны у всех объектов.
В очень редких случаях, потоки в состоянии WAITING могут проснуться из-за так называемой ложной активизации (spurious wakeup).
Поэтому, вызов метода wait(), должен быть в цикле по условию, которому поток должен засыпать.

Все эти методы вызываются только из синхронизированного контекста - синхронизированного блока или метода.

Важная и интересная информация! Метод notify(); “пробуждает” тот поток, который
последним вызывал метод wait(); и именно поэтому поток, работающий с буквой А никогда не
узнает о том, что монитор свободен — поток буквы B “уснул” перед потоком “С”, поток “С”
разбудил поток “B”, условие выполнено не было, поток опять “уснул” и “разбудил” поток “С” и
так по кругу. Это очень неявная особенность метода notify();, о которой следует помнить.
Итак, для того, чтобы наша небольшая программа отработала правильно и вывела
последовательность ABC 10 раз метод notify() нужно заменить на notifyAll();

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

Чем отличается работа метода wait с параметром и без?

A

Один метод wait() бесконечно ждет другой поток, пока не будет вызван метод notify() или notifyAll() на объекте( Состояние потока WAITING).
Другие две вариации метода wait() ставят текущий поток в ожидание на определенное время. По истечении этого времени поток просыпается и продолжает работу. ( Состояние потока TIMED WAITING).

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

Чем отличаются два интерфейса Runnable и Callable?

A

Возвращаемые значения:
Runnable:
является функциональным интерфейсом и имеет единственный метод run () , который не принимает никаких параметров и не возвращает никаких значений.
Callable:
это универсальный интерфейс, содержащий единственный метод call () , который возвращает универсальное значение V
———————————————————————————-
Обработка исключений:
Runnable:
Поскольку в сигнатуре метода не указано условие throws нет способа распространять дальнейшие проверенные исключения.

Callable:
Метод call () Callable содержит предложение «throws Exception», поэтому мы можем легко пробрасывать исключения дальше

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

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

A

Класс java.lang.Thread содержит перечисление static State – , которое определяет его потенциальные состояния. В любой момент времени поток может находиться только в одном из следующих состояний:

NEW – вновь созданный поток, который еще не начал выполнение (он остается в этом состоянии, пока мы не запустим его с использованием метода start ())

RUNNABLE – поток либо запущен, либо готов к выполнению, но ожидает от планировщика потоков выделения процессорного времени.

BLOCKED – Поток может может быть заблокирован, потому что объект или метод,
с которым связана задача потока сейчас используется другим потоком и не
предназначен для одновременного использования. В таком случае поток
самостоятельно ждет освобождения такого объекта или метода. Или ожидается
ввод данных от пользователя, чтение файла – задержка вызвана внешним
непреднамеренным фактором.

WAITING – ожидание до команды notify или notifyAll
любой поток может войти в это состояние, вызвав любой из следующих трех методов:
object.wait ()
thread.join () или
LockSupport.park ()

TIMED WAITING – Поток переходит в режим ожидания по времени. После того,
как время ожидания закончилось, поток снова возвращается в состояние Runnable. Cуществует пять способов поместить поток в состояние TIMED WAITING :
thread.sleep (long millis)
wait (int timeout) или wait (int timeout, int nanos)
thread.join (long millis)
LockSupport.parkNanos
LockSupport.parkUntil

TERMINATED – завершил всех задач потока, выход из метода run.
завершенный поток возобновить нельзя! можно создать только новый поток

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

Что значит приоритет потока?

A

В Java поток (объекту класса Thread) можно установить приоритет
final void setPriority(int level);

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

Приоритет основного потока main - 5
все потоки наследуют это значение, если не установлено другое.

Работать с приоритетами потока можно с помощью двух функций:

void setPriority(int priority) – устанавливает приоритет потока.
Возможные значения priority — MIN_PRIORITY, NORM_PRIORITY и MAX_PRIORITY.

int getPriority() – получает приоритет потока.

Диапазон значений:
от 1 (java.lang.Thread#MIN_PRIORITY)
до 10 (java.lang.Thread#MAX_PRIORITY).
Приоритет по умолчанию 5 (java.lang.Thread#NORM_PRIORITY).

ВЗАИМНАЯ БЛОКИРОВКА или ситуация Dead Lock – это очень неприятная ошибка, когда
два потока находятся в состоянии ожидания объекта - монитора. Это может
произойти по двум причинам:
• Выполнение двух потоков началось в один и тот же момент времени на разных
ядрах
• В двух потоках используются два объекта - монитора, и синхронизация настроена
таким образом, что один поток занимает первый монитор, второй поток занимает
второй монитор, а дальше в первом потоке встречается блок синхронизации по
второму объекту, а у второго потока - по первому. И они будут бесконечно ждать,
когда объекты-мониторы освободятся.

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