Росс Андерсон (англ. Ross J. Anderson, 15 сентября 1956 — 28 марта 2024, Кембридж) — британский учёный, автор более двухсот статей, консультант по инженерной безопасности. Профессор инженерии безопасности в Кембриджском университете. Его достижения в области криптографии включают в себя разработку шифров, обнаружение слабостей во многих системах безопасности и алгоритмах. Является сооснователем списка рассылки Uk-Crypto.
Анируд Девган (родился 15 сентября 1969 года) — индийско-американский учёный в области компьютерных наук и руководитель бизнеса. Как учёный, Девган известен своим вкладом в автоматизацию электронного проектирования , в частности, в моделирование схем , физическое проектирование и вывод , статистическое проектирование и оптимизацию , а также в верификацию и аппаратные платформы.
1947 — Основание ACM (Association for Computing Machinery) — организация, объединяющая компьютерных учёных и инженеров, официально создана.
1968 — в СССР запущена космическая станция «Зонд-5», которая впервые в мире совершила облёт Луны с последующей мягкой посадкой на Землю.
1997 — Зарегистрирован домен Google.com.
#Biography #Birth_Date #Events #15Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Основы ООП в Java
Глава 6. Ключевые модификаторы ООП
static: поля, методы, блоки инициализации
Модификатор static означает "статический" и привязывает элемент к классу, а не к экземпляру (объекту). Static-элементы существуют в одном экземпляре на класс, независимо от количества объектов.
Зачем нужен static:
Общие данные: Для переменных, общих для всех объектов (например, счетчик экземпляров).
Утилиты: Для методов, не зависящих от состояния объекта (например, Math.sqrt()).
Эффективность: Избежать создания объектов для вызова методов.
Инициализация: Блоки для выполнения кода при загрузке класса.
Static — инструмент для класс-уровня логики в ООП, но не злоупотребляйте: он может нарушать инкапсуляцию.
Static поля: Общие переменные класса
Static поля (class variables) принадлежат классу и делятся всеми объектами. Они инициализируются при загрузке класса.
Синтаксис:
Доступ: Через ClassName.fieldName или объект.fieldName (но рекомендуется через класс).
Пример:
Использование:
Нюанс: Static поля инициализируются по умолчанию (0 для чисел, null для объектов). Можно изменить в static блоке.
Static методы: Утилиты класса
Static методы принадлежат классу и вызываются без объекта. Они не имеют доступа к non-static полям/методам (нет this).
Синтаксис:
Пример:
Вызов:
Нюанс: Static методы не override — это method hiding. Вызов зависит от типа ссылки, не объекта.
Static блоки инициализации: Код при загрузке класса
Static блоки — код, выполняющийся один раз при загрузке класса (перед конструкторами).
Синтаксис:
Пример:
Нюанс: Несколько блоков выполняются в порядке объявления. Полезно для сложной инициализации static полей (например, загрузка конфигурации).
Все нюансы static
Доступ и видимость:
Static элементы доступны без объекта, но non-static — нет из static контекста.
Нюанс: Из static метода нельзя this.field или non-static method() — ошибка.
Наследование:
Static поля/методы наследуются, но не override — hiding. ChildClass.staticMethod() скрывает ParentClass.staticMethod().
Нюанс: Вызов через ссылку: Animal a = new Dog(); a.staticMethod() — вызовет Animal.version (зависит от типа ссылки).
Инициализация:
Static поля/блоки инициализируются при первой загрузке класса (class loading).
Нюанс: Lazy loading — не инициализируется, пока не используется.
Ошибки:
Доступ к non-static из static — ошибка компиляции.
Static в интерфейсах: Да, с Java 8 (static методы).
Static классы: Nested классы могут быть static (не зависят от внешнего объекта).
Дизайн:
Избегайте mutable static полей — проблемы в многопоточности.
Используйте для констант (static final), утилит (Math), singleton.
Нюанс: Static блоки для JDBC драйверов или логирования.
Многопоточность: Static поля общие — используйте synchronization для изменений.
Как создать это в IntelliJ IDEA
Static поле/метод: Добавьте static — IDE подскажет доступ.
Static блок: Напишите static {} — IDE форматирует.
Тестирование: Вызовите static через класс — IDE автодополнит.
Полезные советы для новичков
Константы: public static final для глобальных.
Утилиты: Static методы для helper-классов.
Избегайте состояния: Static поля — только immutable.
Тестируйте: Проверьте доступ из static/non-static.
Ресурсы: Oracle Tutorials on Static Members.
#Java #для_новичков #beginner #OOP #static
Глава 6. Ключевые модификаторы ООП
static: поля, методы, блоки инициализации
Модификатор static означает "статический" и привязывает элемент к классу, а не к экземпляру (объекту). Static-элементы существуют в одном экземпляре на класс, независимо от количества объектов.
Зачем нужен static:
Общие данные: Для переменных, общих для всех объектов (например, счетчик экземпляров).
Утилиты: Для методов, не зависящих от состояния объекта (например, Math.sqrt()).
Эффективность: Избежать создания объектов для вызова методов.
Инициализация: Блоки для выполнения кода при загрузке класса.
Static — инструмент для класс-уровня логики в ООП, но не злоупотребляйте: он может нарушать инкапсуляцию.
Static поля: Общие переменные класса
Static поля (class variables) принадлежат классу и делятся всеми объектами. Они инициализируются при загрузке класса.
Синтаксис:
static type fieldName = value;
Доступ: Через ClassName.fieldName или объект.fieldName (но рекомендуется через класс).
Пример:
public class Counter {
public static int count = 0; // Static поле
public Counter() {
count++; // Увеличивает общее значение
}
}
Использование:
public class Main {
public static void main(String[] args) {
new Counter();
new Counter();
System.out.println(Counter.count); // 2
}
}
Нюанс: Static поля инициализируются по умолчанию (0 для чисел, null для объектов). Можно изменить в static блоке.
Static методы: Утилиты класса
Static методы принадлежат классу и вызываются без объекта. Они не имеют доступа к non-static полям/методам (нет this).
Синтаксис:
static returnType methodName(params) { ... }
Доступ: ClassName.methodName().
Пример:
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}
Вызов:
int sum = MathUtils.add(5, 3); // 8
Нюанс: Static методы не override — это method hiding. Вызов зависит от типа ссылки, не объекта.
Static блоки инициализации: Код при загрузке класса
Static блоки — код, выполняющийся один раз при загрузке класса (перед конструкторами).
Синтаксис:
static {
// Код
}
Пример:
public class Config {
public static String appName;
static {
appName = "MyApp"; // Инициализация при загрузке
System.out.println("Класс загружен!");
}
}
Нюанс: Несколько блоков выполняются в порядке объявления. Полезно для сложной инициализации static полей (например, загрузка конфигурации).
Все нюансы static
Доступ и видимость:
Static элементы доступны без объекта, но non-static — нет из static контекста.
Нюанс: Из static метода нельзя this.field или non-static method() — ошибка.
Наследование:
Static поля/методы наследуются, но не override — hiding. ChildClass.staticMethod() скрывает ParentClass.staticMethod().
Нюанс: Вызов через ссылку: Animal a = new Dog(); a.staticMethod() — вызовет Animal.version (зависит от типа ссылки).
Инициализация:
Static поля/блоки инициализируются при первой загрузке класса (class loading).
Нюанс: Lazy loading — не инициализируется, пока не используется.
Ошибки:
Доступ к non-static из static — ошибка компиляции.
Static в интерфейсах: Да, с Java 8 (static методы).
Static классы: Nested классы могут быть static (не зависят от внешнего объекта).
Дизайн:
Избегайте mutable static полей — проблемы в многопоточности.
Используйте для констант (static final), утилит (Math), singleton.
Нюанс: Static блоки для JDBC драйверов или логирования.
Многопоточность: Static поля общие — используйте synchronization для изменений.
Как создать это в IntelliJ IDEA
Static поле/метод: Добавьте static — IDE подскажет доступ.
Static блок: Напишите static {} — IDE форматирует.
Тестирование: Вызовите static через класс — IDE автодополнит.
Полезные советы для новичков
Константы: public static final для глобальных.
Утилиты: Static методы для helper-классов.
Избегайте состояния: Static поля — только immutable.
Тестируйте: Проверьте доступ из static/non-static.
Ресурсы: Oracle Tutorials on Static Members.
#Java #для_новичков #beginner #OOP #static
👍3
Каким Вы видите свое будущее как программиста?
Anonymous Poll
12%
Я буду владельцем крупной IT-компании 🏝
24%
Я буду работать в крупной IT-компании, как минимум на высокой должности 🧑💻
18%
Я запущу свой проект, потом его дорого продам и буду кайфовать на дивиденды 😋
39%
Я хочу просто о стабильную работу со средней зарплатой, чтобы хватало на все для моей семьи ❤️
6%
Свой вариант в комментариях 📞
👍1
Что выведет код?
#Tasks
public class Task150925 {
static int x = 5;
static {
x = 10;
y = 20;
}
static int y = 15;
public static void main(String[] args) {
System.out.println(x + " " + y);
}
}
#Tasks
🤯2
👍4🤯2
Please open Telegram to view this post
VIEW IN TELEGRAM
Сетка
Java for Beginner. Канал в Сетке
Канал для новичков в Java
👍3
Вопрос с собеседований
Что такое virtual threads в Java?🤓
Ответ:
Virtual threads (введены в Java 21) — легковесные потоки, управляемые JVM, а не ОС. Они дешевы в создании и позволяют масштабировать приложения с тысячами потоков.
Пример:
Thread vt = Thread.ofVirtual().start(() -> System.out.println("Virtual thread"));
В отличие от платформенных потоков, виртуальные не привязаны к OS-thread, снижая overhead. Полезны для I/O-bound задач.
#собеседование
Что такое virtual threads в Java?
Ответ:
Virtual threads (введены в Java 21)
Пример:
Thread vt = Thread.ofVirtual().start(() -> System.out.println("Virtual thread"));
В отличие от платформенных потоков, виртуальные не привязаны к OS-thread, снижая overhead. Полезны для I/O-bound задач.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Вале́рий Никола́евич Реше́тников (16 сентября 1943 — 30 ноября 2020) — российский учёный, доктор физ.-мат. наук, руководил Центром визуализации и спутниковых информационных технологий в НИИ системных исследований РАН; внёс вклад в прикладные ИТ-решения для дистанционного зондирования и визуализации больших данных.
Сьюзен Лоис Грэм (родилась 16 сентября 1942 года) — американский учёный в компьютерных науках, профессор UC Berkeley; известна работами по компиляторам, инструментальным средствам разработки и программным системам для масштабируемого программирования.
1959 — В США представлен публике первый коммерческий копировальный аппарат Xerox 914.
#Biography #Birth_Date #Events #16Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Реактивное программирование
Вступление
В современном мире разработки программного обеспечения мы всё чаще сталкиваемся с задачами, где простая последовательная логика уже не справляется. Нагрузки на системы растут экспоненциально: миллионы пользователей ожидают мгновенных ответов, микросервисы обмениваются сотнями запросов в секунду, а данные льются рекой из баз данных, API и внешних сервисов.
Традиционный подход — "запрос приходит, запускается поток, ждём ответа" — начинает давать сбои: система тонет в блокировках, лишних потоках и перерасходе ресурсов.
Представьте: сервер обрабатывает тысячи подключений, но каждый запрос занимает отдельный поток, который висит в ожидании, пока не придёт ответ от сети или диска. Это как пытаться пропустить толпу через узкий коридор — пробки неизбежны.
Чтобы выжать максимум из аппаратных ресурсов и сделать приложения более отзывчивыми, нужно менять способ мышления. Один из ключевых инструментов для этого — реактивное программирование, подход, который фокусируется на обработке потоков данных и событий в асинхронном режиме, без лишних блокировок.
Асинхронщина и её проблемы: от основ к пределам
Что такое асинхронность в программировании?
Это когда программа не стоит на месте, ожидая завершения одной задачи, а продолжает работать с другими. В Java это реализуется через механизмы, позволяющие запускать код параллельно. Но на пути к идеалу было много подводных камней.
Потоки: базовый, но тяжёлый инструмент
Многопоточность в Java появилась ещё в ранних версиях языка. Идея проста: вы создаёте новый поток — это как отдельный "рабочий", который выполняет код независимо от основного.
Код выглядит так:
Внутри метода run() вы пишете, что нужно сделать. На первый взгляд, это решает проблему: пока один поток ждёт ответа от сервера, другой может обрабатывать новый запрос.
Но практика показывает минусы. Каждый поток — это тяжёлый объект: он требует выделения памяти (обычно от 1 МБ на стек), системных ресурсов операционной системы и времени на создание. Если нагрузка растёт — скажем, 10 тысяч одновременных запросов, — вы не сможете создать 10 тысяч потоков: система просто исчерпает ресурсы, и всё упадёт. Ещё одна боль — контекстные переключения: когда процессор переключается между потоками, это стоит CPU-времени, иногда до микросекунд на переключение, что накапливается в большие задержки.
Чтобы смягчить это, в Java ввели ExecutorService — сервис-исполнитель, который управляет пулом потоков. Вы создаёте фиксированный пул, например, Executors.newFixedThreadPool(10), и подаёте задачи:
Теперь потоки переиспользуются: закончил задачу — берёт следующую. Это экономит ресурсы, но не решает корень проблемы. Если в задаче есть блокирующий код — например, чтение из файла или ожидание сети, — поток всё равно "зависает" в ожидании, блокируя место в пуле. Другие задачи ждут в очереди, и под высокой нагрузкой пул исчерпывается. В итоге, асинхронность есть, но она неэффективна: ресурсы тратятся на ожидание, а не на полезную работу.
#Java #middle #Reactor
Вступление
В современном мире разработки программного обеспечения мы всё чаще сталкиваемся с задачами, где простая последовательная логика уже не справляется. Нагрузки на системы растут экспоненциально: миллионы пользователей ожидают мгновенных ответов, микросервисы обмениваются сотнями запросов в секунду, а данные льются рекой из баз данных, API и внешних сервисов.
Традиционный подход — "запрос приходит, запускается поток, ждём ответа" — начинает давать сбои: система тонет в блокировках, лишних потоках и перерасходе ресурсов.
Представьте: сервер обрабатывает тысячи подключений, но каждый запрос занимает отдельный поток, который висит в ожидании, пока не придёт ответ от сети или диска. Это как пытаться пропустить толпу через узкий коридор — пробки неизбежны.
Чтобы выжать максимум из аппаратных ресурсов и сделать приложения более отзывчивыми, нужно менять способ мышления. Один из ключевых инструментов для этого — реактивное программирование, подход, который фокусируется на обработке потоков данных и событий в асинхронном режиме, без лишних блокировок.
Асинхронщина и её проблемы: от основ к пределам
Что такое асинхронность в программировании?
Это когда программа не стоит на месте, ожидая завершения одной задачи, а продолжает работать с другими. В Java это реализуется через механизмы, позволяющие запускать код параллельно. Но на пути к идеалу было много подводных камней.
Потоки: базовый, но тяжёлый инструмент
Многопоточность в Java появилась ещё в ранних версиях языка. Идея проста: вы создаёте новый поток — это как отдельный "рабочий", который выполняет код независимо от основного.
Код выглядит так:
new Thread(() -> { /* ваш код */ }).start();.
Внутри метода run() вы пишете, что нужно сделать. На первый взгляд, это решает проблему: пока один поток ждёт ответа от сервера, другой может обрабатывать новый запрос.
Но практика показывает минусы. Каждый поток — это тяжёлый объект: он требует выделения памяти (обычно от 1 МБ на стек), системных ресурсов операционной системы и времени на создание. Если нагрузка растёт — скажем, 10 тысяч одновременных запросов, — вы не сможете создать 10 тысяч потоков: система просто исчерпает ресурсы, и всё упадёт. Ещё одна боль — контекстные переключения: когда процессор переключается между потоками, это стоит CPU-времени, иногда до микросекунд на переключение, что накапливается в большие задержки.
Чтобы смягчить это, в Java ввели ExecutorService — сервис-исполнитель, который управляет пулом потоков. Вы создаёте фиксированный пул, например, Executors.newFixedThreadPool(10), и подаёте задачи:
executor.execute(() -> { /* код */ });
Теперь потоки переиспользуются: закончил задачу — берёт следующую. Это экономит ресурсы, но не решает корень проблемы. Если в задаче есть блокирующий код — например, чтение из файла или ожидание сети, — поток всё равно "зависает" в ожидании, блокируя место в пуле. Другие задачи ждут в очереди, и под высокой нагрузкой пул исчерпывается. В итоге, асинхронность есть, но она неэффективна: ресурсы тратятся на ожидание, а не на полезную работу.
#Java #middle #Reactor
👍3
Future: обещание результата, но с подвохом
В Java 5 ввели Future — это как "чек" на будущий результат.
Вы подаёте задачу в executor и получаете объект Future, который обещает: "когда-нибудь я дам тебе ответ".
Пример:
Плюс в том, что вы можете продолжать работу, не дожидаясь: пока задача крутится в фоне, основной код идёт дальше. Но чтобы забрать результат, нужно вызвать future.get(). И вот здесь засада: get() блокирует текущий поток до тех пор, пока задача не завершится. Если задача задерживается — скажем, из-за сети, — ваш поток тоже висит в ожидании. Получается, асинхронность иллюзорна: да, запуск асинхронный, но использование результата синхронное и блокирующее. Это как заказать еду по доставке, но стоять у двери, не отходя, пока курьер не приедет. Выигрыш минимален, особенно в веб-приложениях, где запросы должны обрабатываться быстро.
Ещё Future неудобен в композиции: если нужно объединить результаты нескольких задач, приходится вручную ждать каждого get(), что приводит к спагетти-коду с try-catch для ошибок и таймаутами.
CompletableFuture: цепочки действий, но без избавления от ада
Java 8 принесла CompletableFuture — улучшенную версию Future, которая позволяет строить цепочки асинхронных операций без блокировок на get(). Теперь результат можно обрабатывать через "колбэки" — функции, которые вызываются автоматически по завершении.
Пример:
Есть методы для комбинации: thenCompose для последовательных цепочек, thenCombine для параллельного объединения результатов, handle для обработки ошибок. Это шаг вперёд: код становится declarative (описательным), вы фокусируетесь на "что сделать", а не "как ждать". Нет нужды в ручном get() — всё течёт само.
Но радость недолговечна. Когда приложение усложняется — например, нужно асинхронно запросить данные из базы, потом из внешнего API, обработать ошибки и объединить, — цепочки лямбд растут в "callback-ад" (ад колбэков): вложенные функции, которые трудно читать, отлаживать и тестировать. Один уровень — ок, но пять-шесть — и код превращается в пирамиду, где сложно отследить поток выполнения.
Ещё хуже: под капотом блокировки никуда не делись. Если в цепочке есть блокирующий вызов — например, Thread.sleep() для симуляции задержки или JDBC-драйвер, который ждёт ответа от базы, блокируя поток, — весь CompletableFuture теряет преимущество. Поток из пула всё равно занят ожиданием, и под нагрузкой система снова захлёбывается. Плюс, управление ошибками в цепочках требует осторожности: одна ошибка может сломать всю последовательность, если не обработать timely.
В итоге, CompletableFuture дал выразительный синтаксис и удобство для простых сценариев, но не решил системные проблемы: ресурсы тратятся впустую на блокировки, сложность растёт, а масштабируемость под вопросом.
#Java #middle #Reactor
В Java 5 ввели Future — это как "чек" на будущий результат.
Вы подаёте задачу в executor и получаете объект Future, который обещает: "когда-нибудь я дам тебе ответ".
Пример:
ExecutorService executor = Executors.newFixedThreadPool(10); Future<String> future = executor.submit(() -> { Thread.sleep(1000); return "Привет"; });.
Плюс в том, что вы можете продолжать работу, не дожидаясь: пока задача крутится в фоне, основной код идёт дальше. Но чтобы забрать результат, нужно вызвать future.get(). И вот здесь засада: get() блокирует текущий поток до тех пор, пока задача не завершится. Если задача задерживается — скажем, из-за сети, — ваш поток тоже висит в ожидании. Получается, асинхронность иллюзорна: да, запуск асинхронный, но использование результата синхронное и блокирующее. Это как заказать еду по доставке, но стоять у двери, не отходя, пока курьер не приедет. Выигрыш минимален, особенно в веб-приложениях, где запросы должны обрабатываться быстро.
Ещё Future неудобен в композиции: если нужно объединить результаты нескольких задач, приходится вручную ждать каждого get(), что приводит к спагетти-коду с try-catch для ошибок и таймаутами.
CompletableFuture: цепочки действий, но без избавления от ада
Java 8 принесла CompletableFuture — улучшенную версию Future, которая позволяет строить цепочки асинхронных операций без блокировок на get(). Теперь результат можно обрабатывать через "колбэки" — функции, которые вызываются автоматически по завершении.
Пример:
CompletableFuture.supplyAsync(() -> { return "Данные"; }).thenApply(data -> { return data.toUpperCase(); }).thenAccept(System.out::println);.
Здесь supplyAsync запускает задачу асинхронно, thenApply преобразует результат (например, переводит в верхний регистр), thenAccept выводит его.
Есть методы для комбинации: thenCompose для последовательных цепочек, thenCombine для параллельного объединения результатов, handle для обработки ошибок. Это шаг вперёд: код становится declarative (описательным), вы фокусируетесь на "что сделать", а не "как ждать". Нет нужды в ручном get() — всё течёт само.
Но радость недолговечна. Когда приложение усложняется — например, нужно асинхронно запросить данные из базы, потом из внешнего API, обработать ошибки и объединить, — цепочки лямбд растут в "callback-ад" (ад колбэков): вложенные функции, которые трудно читать, отлаживать и тестировать. Один уровень — ок, но пять-шесть — и код превращается в пирамиду, где сложно отследить поток выполнения.
Ещё хуже: под капотом блокировки никуда не делись. Если в цепочке есть блокирующий вызов — например, Thread.sleep() для симуляции задержки или JDBC-драйвер, который ждёт ответа от базы, блокируя поток, — весь CompletableFuture теряет преимущество. Поток из пула всё равно занят ожиданием, и под нагрузкой система снова захлёбывается. Плюс, управление ошибками в цепочках требует осторожности: одна ошибка может сломать всю последовательность, если не обработать timely.
В итоге, CompletableFuture дал выразительный синтаксис и удобство для простых сценариев, но не решил системные проблемы: ресурсы тратятся впустую на блокировки, сложность растёт, а масштабируемость под вопросом.
#Java #middle #Reactor
👍3
Callback-ад и блокировки: кульминация проблем
Callback-ад — это когда колбэки (функции обратного вызова) наслаиваются друг на друга, делая код нечитаемым. В CompletableFuture это проявляется в глубоких цепочках: thenApply внутри thenCompose, с handle для ошибок. Отладка — кошмар: где именно сломалось? Тестирование — тоже, потому что асинхронность добавляет неопределённость в порядок выполнения.
Блокировки — это когда код "зависает" в ожидании внешнего события, не давая потоку работать с другими задачами. В Java многие библиотеки (как старые IO или JDBC) блокирующие по природе: они используют системные вызовы, которые стопорят поток. Даже в асинхронных конструкциях, если внутри лямбды такая блокировка, весь пул потоков может исчерпаться. Представьте сервер с 100 потоками: 100 запросов с задержкой — и новые ждут в очереди, вызывая таймауты.
Это приводит к неэффективности: CPU простаивает, память тратится на "спящие" потоки, а под пиковой нагрузкой система не масштабируется горизонтально.
Почему нужен новый подход: реактивное программирование
Мы дошли до предела традиционных моделей. Потоки хороши для CPU-bound задач (расчёты), но тяжёлые для IO-bound (сеть, диски). Future дал обещания, но не избавил от блокировок. CompletableFuture улучшил код, но оставил callback-ад и зависимость от неблокирующих библиотек.
Здесь на сцену выходит реактивное программирование — подход, где мы думаем в терминах потоков данных и событий, а не отдельных задач. Вместо "запрос → блокировка в потоке → ответ" мы строим конвейеры: данные приходят асинхронно по мере готовности, обработка идёт реактивно, без выделения потока на каждое ожидание. Это как перейти от конвейера с паузами к непрерывному потоку. В следующих постах разберём Reactive Streams, Flux/Mono в Project Reactor и как это решает проблемы.
#Java #middle #Reactor
Callback-ад — это когда колбэки (функции обратного вызова) наслаиваются друг на друга, делая код нечитаемым. В CompletableFuture это проявляется в глубоких цепочках: thenApply внутри thenCompose, с handle для ошибок. Отладка — кошмар: где именно сломалось? Тестирование — тоже, потому что асинхронность добавляет неопределённость в порядок выполнения.
Блокировки — это когда код "зависает" в ожидании внешнего события, не давая потоку работать с другими задачами. В Java многие библиотеки (как старые IO или JDBC) блокирующие по природе: они используют системные вызовы, которые стопорят поток. Даже в асинхронных конструкциях, если внутри лямбды такая блокировка, весь пул потоков может исчерпаться. Представьте сервер с 100 потоками: 100 запросов с задержкой — и новые ждут в очереди, вызывая таймауты.
Это приводит к неэффективности: CPU простаивает, память тратится на "спящие" потоки, а под пиковой нагрузкой система не масштабируется горизонтально.
Почему нужен новый подход: реактивное программирование
Мы дошли до предела традиционных моделей. Потоки хороши для CPU-bound задач (расчёты), но тяжёлые для IO-bound (сеть, диски). Future дал обещания, но не избавил от блокировок. CompletableFuture улучшил код, но оставил callback-ад и зависимость от неблокирующих библиотек.
Здесь на сцену выходит реактивное программирование — подход, где мы думаем в терминах потоков данных и событий, а не отдельных задач. Вместо "запрос → блокировка в потоке → ответ" мы строим конвейеры: данные приходят асинхронно по мере готовности, обработка идёт реактивно, без выделения потока на каждое ожидание. Это как перейти от конвейера с паузами к непрерывному потоку. В следующих постах разберём Reactive Streams, Flux/Mono в Project Reactor и как это решает проблемы.
#Java #middle #Reactor
👍4
Как часто вы используете многопоточку в своем коде?
Anonymous Poll
3%
Практически каждый день.
14%
Периодически приходится.
23%
Очень редко. Раз на 10-20 проектов.
26%
Вообще использовал 1 раз.
34%
Никогда не приходилось использовать.
👍1
Что выведет код?
#Tasks
import java.util.concurrent.*;
public class Task160925 {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
Thread.sleep(1000);
return "Done";
});
System.out.println(future.get(500, TimeUnit.MILLISECONDS));
executor.shutdown();
}
}
#Tasks
👍2
👍1