Многопоточность глазами разработчика
HTML-код
- Опубликовано: 1 июн 2024
- В этом виде мы изучим теоретические основы и получим практические навыки работы с многопоточностью и параллелизмом на примере языка программирования Java.
Ссылка на Github репозиторий с примерами кода:
github.com/proselytear/javaco...
Дружное сообщество:
t.me/pse_club
Материалы для разработчиков:
proselyte.net/
Рекомендуемые материалы:
Java Concurrency In Practice
www.amazon.com/Java-Concurren...
JLS - Memory Model
docs.oracle.com/javase/specs/...
00:00:00 - Введение
00:01:20 - Основы многопоточности
00:09:44 - Самоконтроль (основы многопоточности)
00:10:06 - Работа с потоками
00:11:17 - Создание потока с помощью класса Thread
00:14:06 - Создание потока с помощью интерфейса Runnable
00:15:27 - Работа с методом Thread.sleep()
00:16:45 - Работа методом join()
00:18:54 - Приоритеты потоков
00:21:17 - daemon потоки
00:23:27 - Самоконтроль (работа с потоками)
00:23:50 - Синхронизация данных
00:28:10 - Мьютексы и ключевое слово synchronized
00:31:01 - Встроенный монитор (intrisic lock)
00:32:39 - Использование объекта в качестве монитора
00:34:19 - Работа с ReentrantLock
00:41:56 - Работа с Semaphore
00:45:19 - Работа с Exchanger
00:47:05 - Deadlock vs Livelock vs Starvation
00:49:35 - Пример Deadlock
00:52:38 - Пример Livelock
00:54:45 - Пример Starvation
00:56:07 - Механизм CAS
01:00:42 - Самоконтроль (синхронизация данных)
01:01:00 - Потокобезопасные коллекции
01:02:42 - Работа с synchorized ArrayList
01:02:36 - Работа с BlockingQueue
01:05:26 - Работа с PriorityQueue
01:07:06 - Работа с CopyOnWriteArray
01:10:04 - Работа с ConcurrentHashMap
01:12:33 - Самоконтроль (потокобезопасные коллекции)
01:12:48 - Executor Framework
01:14:47 - Работа с SingleThreadPool
01:15:54 - Работа с FixedThreadPool
01:17:35 - Работа со ScheduledThreadPool
01:19:08 - Работа с СachedThreadPool
01:20:29 - Концепция Callable и Future
01:23:31 - ForkJoin Framework
01:28:25 - Виртуальные потоки
01:34:39 - Заключение
Это бриллиант из мира видео про программирование. Мало кому удается настолько подробно объяснить тяжелые темы доступным способом, без воды, и с максимальным количеством примеров, браво!
Большое спасибо за отзыв!
Последовательная, структурированная подача.
На одном дыхании смотрится, спасибо!
Спасибо за отзыв!
Это лучшее видео про многопоточность!!!!
Большое спасибо за отзыв!
Лучшее объяснение что я видел, спасибо!
Спасибо за отзыв!
Готовлюсь к собеседованиям, как раз изучаю тему многопоточности, и тут такое видео от Евгения.
Коммент пишу до просмотра, потому что знаю, будет топ!
Спасибо за комментарий и удачи на собеседовании :)
Очень простым язым про сложное. Спасибо!
Спасибо за отзыв!
Топовый материал + все структурированно!
Большое спасибо за отзыв!
Огромное спасибо за ваш труд, Евгений
Спасибо за поддержку!
Женя, большое спасибо за экспертизу! Очень приятно слушать тебя. Без воды, чётко и с примерами на экране. Такие знания продают, а ты делишься ими безвозмездно. Это просто не передать словами.
Огромное человеческое спасибо.
Большое спасибо за поддержку!
Спасибо Евгений 😊
Спасибо за отзыв!
Супер подача материала, и сам материал - все основы по многопоточности в одном видео 🔥 Спасибо большое!
Спасибо за отзыв!
Большое Спасибо. Очень нужная вещь
Спасибо за поддержку!
Большое спасибо за структурированную, грамотно поданную информацию!
Спасибо за отзыв!
Спасибо, Женя! Огромная работа, ты молодец!)
Спасибо, Юра :)
Евгений, спасибо вам за ваш труд! Очень полезное видео👍
Спасибо за поддержку!
Евгений, спасибо! Освежил знания. Очень было интересно и не скучно
Спасибо за отзыв!
Контент как всегда на высоте!
Спасибо.
Спасибо за отзыв!
Комментарий в поддержку канала. Очень качественная и хорошо структурированная подача. Можно использовать как лекции для новичков)
Большое спасибо за поддержку!
Супер! Спасибо, Женя!
Большое спасибо за отзыв!
Спасибо за видео про многопоточность! Очень понятно объяснили🔥🔥🔥
Спасибо за отзыв, Эльнар!
В поддержку канала! Спасибо за видео!
Спасибо за поддержку!
Евгений, спасибо за видео и примеры)
Спасибо за поддержку!
Спасибо за труды!
Спасибо за поддержку!
Как всегда все максимально понятно, спаси большое за твой труд!
Большое спасибо за отзыв!
спасибо большое! прекрасно поданный материал
Большое спасибо за отзыв!
Отличное видео. Буду периодически пересматривать
Спасибо за отзыв!
Благодарю за видео, что-то новое подчерпнул для себя. Да и повторенье не помешает.
Спасибо за отзыв!
Имба подъехала)
Спасибо!
Спасибо за поддержку!
Большое спасибо за видео 🤝
Спасибо за поддержку!
Сеппер. Материал прям разжеван. Подача на высоте. Спасибо за труд.
Спасибо за поддержку!
Спасибо, стало более понятно, особенно, про executors и forkjoin, не разбирался с этим)
Спасибо за комментарий!
Рад, что материал оказался полезен.
Как всегда, лучший 😊
Спасибо за отзыв :)
как всегда -> безупречно!👍
Спасибо за комментарий!
Огромное спасибо за видео.
Увидел небольшую недоработку хотел бы указать на нее.
К сожалению на 29:59 некорректный пример для наглядного показа как работает синхронизация для двух разных счетчиков.
Проблема которую я тут вижу в том, что вы в разных потоках, инкрементируете (пусть и потоконебезопасно) разные счетчики. Т.е. даже теоретически они не смогут повлиять друг на друга, а следовательно будут выводиться всегда верно. Даже если не будут синхронизированы.
Большое спасибо за отзыв и замечание. Здесь больше упор был на введение в мьютексы, но я должным образом не акцентировал на этом внимание, поэтому этот пример вызывает недоумение.
Еще раз спасибо!
@@EugeneSuleimanov вам огромное спасибо за контент!
Как раз готовлюсь к собесу. Спасибо большое
Спасибо за отзыв и удачи на собеседовании.
Объяснение виртуальных потоков потрясающее! Привет из Армении, дорогой Евгений.
Большое спасибо за отзыв!
Спасибо большое)
Спасибо за комментарий!
Это самое годное, что я видел за последнее время (честно)
Можно предлагать темы для видео ?)
Спасибо за отзыв!
Предлагать можно, но уже есть свой план на ближайшие 6 месяцев.
@@EugeneSuleimanov хотел предложить довольно интересную тему - реализация OTP (one time password / двухфакторка) на спринге. По ней довольно мало материала в интернете, и то, что есть - сделано очень коряво и не секьюрно. Я видел ваши видео, видел вашу архитектуру, и мне кажется, у вас бы получилось реализовать хороший прототип :)
Шедеврально. Фундаментальная систематизация темы многопоточности. Достойно быть оформлено как раздел учебника. Персональная благодарность за наглядное объяснение использования Conditions у ReentrantLocks.
Большое спасибо за отзыв!
спасибо огромное)
Спасибо за отзыв :)
Полезно!
Спасибо за поддержку!
Лайк сразу !)
Спасибо за поддержку!
Спасибо ❤
Спасибо за поддержку!
Как всегда уровень
Спасибо за отзыв!
Лекция топ
Спасибо за комментарий!
здравствуй, на 34.57 нашел противоречие насчет освобождения мониторов. В Java внутренние мониторы (или мониторы объектов) не могут быть освобождены "любым" потоком. Мониторы объектов обычно захватываются и освобождаются тем же потоком, который вошел в блок synchronized для данного объекта.
Лучший блогер по джава!
Спасибо за поддержку!
Спасибо Евгений! Хочу спросить у вас, точно так как у .NET’e работает потоки как у Java ? Потому что я .NET разработчик.Заранее спасибо!
Не могу понять, почему возможна ситуация, когда два раза будет напечатан PING (46:39).
Если я правильно понял, то поток блокируется до момента, пока не будет выполнен обмен (когда другой поток инициирует обмен).
Как поток может два раза выполнить: exchange() + print(), если другой поток должен как минимум один раз сделать exchange() + print(), что исключает возможность вывода в консоль дважды например, PING?
Евгений, спасибо за лекцию - лучшее, что я видел по многопоточке освещающее практически все аспекты.
Два вопроса:
1. В ConcurrentHashMap почему блокировка идет не по бакету а по "сегметам из 4х бакетов" - какое логическое объяснение?
2. В чем смыл SingleThreadPoolExecutor если есть Fixed? доставить из пула "один из одного" не пересоздавая?
если бы блокировка была на уровне одного бакета, потребовалось бы больше блокировок и, соответственно, выше были бы накладные расходы на управление ими.
Так как блокировка происходит на уровне сегментов, несколько потоков могут одновременно обрабатывать различные сегменты карты, что увеличивает производительность многопоточных операций.
Очень хорошие вопросы, надеюсь Евгений ответит
34:10 а можно ли назвать эти лок-объекты не мониторами, а именно мьютексами? Насколько я понимаю, реализация монитора происходит с помощью блока synchronized, а в параметры этого блока мы передаем мьютекс, т.е. значение (объект/класс), на котором синхронизируемся?
Спасибо за вопрос. Да, можно назвать и так, но в Java чаще всего используется термин монитор.
Добрый день и еще такой вопрос, виртуальный поток это абстракция над чем? Я так же смотрел материал где говорится, что инструменты типа corutine and gorutine , это frameworks на уровне языка, позволяющий писать асинхронный код как последовательный
Спасибо за вопрос!
Это абстракция над обычными потоками операционной системы.
Относительно coroutine и goroutine - это механизмы, предоставляемые различными языками программирования (например, Kotlin для coroutine, Go для goroutine), которые обеспечивают лёгкие "зелёные" потоки выполнения. Они позволяют писать асинхронный код так, как будто он выполняется последовательно, что облегчает асинхронное программирование и уменьшает накладные расходы на создание потоков.
@@EugeneSuleimanov тогда, по -сути поток Операционной системы, это время Одного из процессоров, которое выделено , на выполнение задачи., в рамках процесса программы. Но будет ли оно выполнено последовательно или попеременно, Или параллельно, т.е другим процессором или ядром, от нас не зависит, управлять этим нельзя, можно лишь направлять. Я правильно понимаю?
@@maksimus.ssirotkin1124 по определению потока - не совсем согласен. Но по части контроля - верно, в Java мы не можем это контролировать.
101 мой друг, хочу в backend, выбираю между PHP, Golang, Node.js, Java, что посоветуешь, чтобы легче было устроиться на работу с перспективой? Или с какого языка посоветуешь начать?
Спасибо за комментарий!
Я предвзят и советовал бы Java :)
добрый день.
Не понял на 34.19
Как может быть что внутренний монитор может быть освобожден любым потоком?
ведь если Т1 захватит монитор текущего объекта, то Т2 поток будет ждать пока монитор не освободится.
Добрый день, спасибо за вопрос.
Как пример - метод notifyAll() у класса Object.
Дякую! Супер!
Спасибо за поддержку!
Здравствуйте, такой вопрос, за счет чего достигается ускорение,если потоков больше чем ядер, и другой вопрос, можно ли средствами Java, передать выполнение задачи или пула задач, конкретному процессору или процессору, но чтобы он не отвлекался, на выполнение других задач?
Спасибо за вопросы!
По первому вопросу:
В случае многопоточных вычислений, где задачи могут быть разделены на независимые подзадачи, параллельное выполнение на нескольких потоках может значительно ускорить общее время выполнения.
По второму вопросу:
В Java нет прямого способа явно указать процессор, на котором должна выполняться задача.
Надеюсь, я верно понял вопросы и смог дать на них ответ.
Привет! На 30:21 ведь нет необходимости использовать synchronized на методах? Т.к. каждый поток работает со своей переменной, аномалий никаких не происходит.
Спасибо за вопрос! Да, все верно, здесь просто подводка к внутренним монитором.
Поправьте, если не прав, но мне кажется что на 12:03 упоминается пример про SimpleCounterDemo, которого нет в данном видео выше
Да, вы правы, спасиб за уточнение, вероятнее всего выпало при монтаже.
github.com/proselytear/javaconcurrency/blob/main/src/main/java/net/proselyte/concurrency/threadsintro/SimpleCounterDemo.java
Здесь ссылка на этот пример.
Евгений, огромное спасибо за видео. С помощью Ваших роликов я разобрался во многих аспектах Java.
Если возможно, подскажите, пожалуйста, зачем в классе IncrementTwoCountersSynchronizedDemo делать synchronized два метода по инкременту счетчиков? Если каждый поток юзает только свой метод и свой счетчик, и у потоков нет общих ресурсов. Я с десяток раз запускал код без синхронайзд и всегда ответ был один и тот же. Спасибо за ответ!
Спасибо за отзыв и ваш вопрос. Здесь была демонстрация того, что мы можем использовать несколько таких блоков внутри класса и подводка к блокировке через объект.
@@EugeneSuleimanov Понял, спасибо!
Вот да, хотел написать такой же коммент, но сначала решил поискать среди имеющихся :) согласен, что пример странный, т.к. синхронизация там вообще ничего не дает.
Евгений, а где ваши выступления на конференциях посмотреть можно?)
Спасибо за комментарий!
По видео не уверен, что созвонились, не самые мейнстримные площадки были.
Евгений, спасибо за очень крутое видео. Все очень подробно и доступно показано.
На 35:38 вы упомянули слово "семантика", это очень сложное слово, не понятно что оно означает. Могли бы вы дать объяснение что оно значит в данном контексте?
Я так понял, что возможно под "семантикой" в данном случае имеется в виду функционал или способ работы/применения.
@@ratmirv в данном контексте "семантика" означает набор гарантий, которые будут выполнены в ходе исполнения программы. Я знал ответ на этот вопрос, прежде чем спрашивать. Просто хотел услышать ответ Евгения. Возможно он будет отличаться от моего определения.
Контентище!
Спасибо за комментарий!
А почему не рассказывает про happens-before?
21:10 а зачем в итоге знать приоритеты если они по факту не работают?
Кажется про volatile вопрос есть, а что это нету
Разве открытые потоки не нужно закрывать?
Спасибо за вопрос. Не могли бы вы немного уточнить вопрос?
@@EugeneSuleimanov каждый поток надо закрывать, разве нет?
@@kozhuhovIvanон же говорил. В 21 джаве Executors стали импл. Closeable. А если ты про обычные потоки, то нахрена их закрывать, и как ты их закроешь. Метод .stop() давно deprecated
@kozhuhovIvan Вы, наверное, путаете с ресурсами, которые действительно надо закрывать (например, объект, который работает с файловой системой или сетью). Потоки закрывать не нужно, они завершаются сами, когда завершают выполнение своей работы.
+
Спасибо за поддержку!
Если у кого-то зависает постоянно, как у меня, в примере на 38:38. Попробую объяснить (если не прав, поправьте)
Если первый поток первый захватывает lock и выполняет firstMethodCalled.signal(), пока второй поток ждёт lock, то когда второй поток получит lock и встанет на ожидание firstMethodCalled.await(), то его некому будет разбудить.
Вариант решения, как я понял, заключается в оборачивании firstMethodCalled.await() в конструкцию while, где условием будет флаг, который меняет первый поток. Это позволяет добиться:
1. Не вставать в ожидание, если метод first() выполнился первым
2. Избежать ложных пробуждений, если метод second() выполнится первым, и поток будет ожидать
У меня такая же проблема, спасибо за решение) Не понимаю, как у автора ни разу не возникло такой ситуации.
Тоже самое, рандомно паркуются либо Т2 и Т3, либо Т3
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private final Condition firstMethodCalled = lock.newCondition();
private final Condition secondMethodCalled = lock.newCondition();
private final AtomicInteger count1 = new AtomicInteger(0);
private final AtomicInteger count2 = new AtomicInteger(0);
public void first() {
lock.lock();
try {
System.out.println("first");
firstMethodCalled.signal();
count1.incrementAndGet();
} finally {
lock.unlock();
}
}
public void second() {
lock.lock();
try {
while (count1.get() == 0) {
firstMethodCalled.await();
}
System.out.println("second");
secondMethodCalled.signal();
count2.incrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void third() {
lock.lock();
try {
while (count2.get() == 0) {
secondMethodCalled.await();
}
System.out.println("third");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}