14-15. Основы многопоточного программирования Flashcards
Чем отличается процесс от потока?
Процесс — это совокупность кода и данных, разделяющих общее виртуальное адресное пространство. Чаще всего одна программа состоит из одного процесса, но бывают и исключения (например, браузер Chrome создает отдельный процесс для каждой вкладки, что дает ему некоторые преимущества, вроде независимости вкладок друг от друга). Процессы изолированы друг от друга, поэтому прямой доступ к памяти чужого процесса невозможен (взаимодействие между процессами осуществляется с помощью специальных средств).
Один поток – это одна единица исполнения кода. Каждый поток последовательно выполняет инструкции процесса, которому он принадлежит, параллельно с другими потоками этого процесса.
Каким образом можно создать поток?
Каждый процесс имеет хотя бы один выполняющийся поток. Тот поток, с которого начинается выполнение программы, называется главным. В языке Java, после создания процесса, выполнение главного потока начинается с метода main(). Затем, по мере необходимости, в заданных программистом местах, и при выполнении заданных им же условий, запускаются другие, побочные потоки.
В языке Java поток представляется в виде объекта-потомка класса Thread. Этот класс инкапсулирует стандартные механизмы работы с потоком.
Запустить новый поток можно двумя способами:
Способ 1:
Создать объект класса Thread, передав ему в конструкторе нечто, реализующее интерфейс Runnable. Этот интерфейс содержит метод run(), который будет выполняться в новом потоке. Поток закончит выполнение, когда завершится его метод run().
Способ 2:
Создать потомка класса Thread и переопределить его метод run():
Как мы можем получить текущий поток?
С помощью метода в классе Thread.currentThread();
Что делают методы isAlive и join?
Метод join()
В Java предусмотрен механизм, позволяющий одному потоку ждать завершения выполнения другого. Для этого используется метод join(). Например, чтобы главный поток подождал завершения побочного потока myThready, необходимо выполнить инструкцию myThready.join() в главном потоке. Как только поток myThready завершится, метод join() вернет управление, и главный поток сможет продолжить выполнение.
Метод join() имеет перегруженную версию, которая получает в качестве параметра время ожидания. В этом случае join() возвращает управление либо когда завершится ожидаемый поток, либо когда закончится время ожидания. Подобно методу Thread.sleep() метод join может ждать в течение миллисекунд и наносекунд – аргументы те же.
С помощью задания времени ожидания потока можно, например, выполнять обновление анимированной картинки пока главный (или любой другой) поток ждёт завершения побочного потока, выполняющего ресурсоёмкие операции.
Необходимое условие работы метода join() - обернуть в конструкцию try-catch. Вызывающий их код должен перехватывать исключение InterruptedException, которое они бросают при прерывании во время ожидания.
Какие способы синхронизации существуют в java?
Для обеспечения синхронизации в Java
реализован прием , называемый
монитором и ключевое слово synchronized
Что такое монитор?
Монитор - это механизм управления, хранящий только один поток исполнения. Как только
поток исполнения войдет в монитор, все другие потоки исполнения должны
ожидать до тех пор, пока тот не покинет монитор. Монитор служит для защиты общих ресурсов от одновременного использования несколькими
потоками исполнения.
Для монитора в Java отсутствует отдельный класс вроде Monitor. Вместо этого
у каждого объекта имеется свой неявный монитор, вход в который осуществляется
автоматически, когда для этого объекта вызывается синхронизированный метод.
Расскажите про методы работы с ключевым словом synchronized?
Для использования синхронизации
предусмотрено ключевое слово synchronized
Мы можем использовать synchronized как целиком на метод или если нет необходимости,
синхронизировать весь метод, применить только на блок кода
Для чего используется ключевое слово volatile?
Его необходимо использовать для переменных, которые используются разными потоками. Это связано с тем, что значение переменной, объявленной без volatile, может кэшироваться отдельно для каждого потока, и значение из этого кэша может различаться для каждого из них. Объявление переменной с ключевым словом volatile отключает для неё такое кэширование и все запросы к переменной будут направляться непосредственно в память.
Как работают методы wait, notify, notifyAll из класса Object?
wait(): освобождает монитор и переводит вызывающий поток в состояние ожидания (блокирует выполнение метода) до тех пор, пока другой поток не вызовет метод notify() для этого монитора
notify(): продолжает работу потока в рамках одного монитора, у которого ранее был вызван метод wait()
notifyAll(): возобновляет работу всех потоков, у которых ранее был вызван метод wait()
Все эти методы вызываются только из синхронизированного контекста - синхронизированного блока или метода.
Чем отличается работа метода wait с параметром и без?
Один метод wait() бесконечно ждет другой поток, пока не будет вызван метод notify() или notifyAll() на объекте. Другие две вариации метода wait() ставят текущий поток в ожидание на определенное время. По истечении этого времени поток просыпается и продолжает работу.
Чем отличаются два интерфейса Runnable и Callable?
Runnable - это основной интерфейс, предоставленный для представления многопоточных задач, а Callable - улучшенная версия Runnable , добавленная в Java 1.5.
Оба интерфейса предназначены для представления задачи, которая может выполняться несколькими потоками. Задачи Runnable можно запускать с помощью класса Thread или ExecutorService , тогда как Callable можно запускать только с использованием ExecutorService.
———————————————————————————-
Возвращаемые значения:
Runnable:
является функциональным интерфейсом и имеет единственный метод run () , который не принимает никаких параметров и не возвращает никаких значений.
Callable:
это универсальный интерфейс, содержащий единственный метод call () , который возвращает универсальное значение V
———————————————————————————-
Обработка исключений:
Runnable:
Поскольку в сигнатуре метода не указано условие throws нет способа распространять дальнейшие проверенные исключения.
Callable:
Метод call () Callable содержит предложение «throws Exception», поэтому мы можем легко пробрасывать исключения дальше
В каких состояниях может быть поток в java?
Класс java.lang.Thread содержит перечисление static State – , которое определяет его потенциальные состояния. В любой момент времени поток может находиться только в одном из следующих состояний:
NEW – вновь созданный поток, который еще не начал выполнение (он остается в этом состоянии, пока мы не запустим его с использованием метода start ())
RUNNABLE – либо запущен, либо готов к выполнению, но ожидает от планировщика потоков выделения времени работы с ЦП
BLOCKED – Он переходит в это состояние, когда ожидает блокировки монитора и пытается получить доступ к фрагменту кода, заблокированному другим потоком.
WAITING – поток находится в состоянии WAITING , когда он ожидает, пока какой-либо другой поток выполнит определенное действие.
[Согласно JavaDocs], любой поток может войти в это состояние, вызвав любой из следующих трех методов:
object.wait ()
thread.join () или
LockSupport.park ()
TIMED WAITING – поток находится в состоянии TIMED WAITING, когда ожидает, пока другой поток выполнит определенное действие в течение установленного промежутка времени. Cуществует пять способов поместить поток в состояние TIMED WAITING :
thread.sleep (long millis)
wait (int timeout) или wait (int timeout, int nanos)
thread.join (long millis)
LockSupport.parkNanos
LockSupport.parkUntil
TERMINATED – завершил выполнение
Что значит приоритет потока?
Приоритеты потоков
Каждый поток в системе имеет свой приоритет. Приоритет – это некоторое число в объекте потока, более высокое значение которого означает больший приоритет. Система в первую очередь выполняет потоки с большим приоритетом, а потоки с меньшим приоритетом получают процессорное время только тогда, когда их более привилегированные собратья простаивают.
Работать с приоритетами потока можно с помощью двух функций:
void setPriority(int priority) – устанавливает приоритет потока. Возможные значения priority — MIN_PRIORITY, NORM_PRIORITY и MAX_PRIORITY.
int getPriority() – получает приоритет потока.