25698
Все самое полезное для Java-разработчика в одном канале. Список наших каналов: https://t.me/proglibrary/9197 Обратная связь: @proglibrary_feedback_bot По рекламе: @proglib_adv Прайс: @proglib_advertising
Enterprise AI: внедряем агентов в сложные бизнес-системы
Для Java-разработчика ИИ-агенты — это новый этап автоматизации процессов. Поймите, как проектировать автономные модули, которые могут быть интегрированы в общую корпоративную архитектуру.
Курс «Углубленные AI-агенты» даст вам фундаментальную базу.
Чему мы научим:
— проектирование мультиагентных структур и связей;
— работа с актуальными фреймворками CrewAI и LangGraph;
— использование RAG-систем для работы с данными;
— оркестрация и масштабирование ИИ-решений.
Курс уже стартовал, успейте присоединиться к группе.
🚀 Записаться на основной курс
Если сомневаетесь — просто посмотрите вводное занятие.
😮 Топ-вакансий для джавистов за неделю
Java Developer (Middle) — 200 000 — 250 000 ₽ — удалёнка
Middle / Senior Java Developer — офис/гибрид (Москва)
Java Developer (Middle / Senior) — удалёнка
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🕯 Модели многопоточности: что выбирают разные языки
Давайте разберем три принципиально разных подхода к многопоточности и посмотрим, к чему они приводят на практике.
➡️ Модель 1: Event Loop (Python, JavaScript/Node.js)
▪️ Суть: один OS-поток на процесс. Runtime сам переключает контекст между задачами.
В CPython есть GIL (Global Interpreter Lock) — мьютекс, который позволяет выполнять байткод только одному потоку за раз. Это сделано для упрощения управления памятью через reference counting. В JavaScript модель изначально однопоточная — event loop обрабатывает задачи последовательно.
▪️Что это значит на практике
— Один инстанс сервиса = одно ядро процессора.
— Для использования 16 ядер нужно запустить 16 процессов + балансировщик.
— Потоки в Python/JS — это логическая абстракция, не настоящие OS threads.
— Для CPU-intensive задач в Python используют multiprocessing (отдельные процессы с изолированной памятью).
✔️ Плюсы
— Простой код без race conditions и deadlocks.
— Не нужны сложные примитивы синхронизации.
— Идеально для I/O-bound нагрузки (сеть, БД).
❌ Минусы
— Усложненная инфраструктура (больше процессов, межпроцессное взаимодействие через очереди/БД).
— Процессы изолированы — нет shared memory.
— Сложнее использовать многоядерность.
➡️ Модель 2: Platform Threads (Traditional Java)
▪️ Суть: 1:1 mapping между Java Thread и OS thread. Планировщик ОС управляет всеми потоками.
Когда вы создаете new Thread() в классической Java, вы напрямую создаете OS thread. Все потоки конкурируют за CPU время через планировщик ОС. У каждого потока ~1 МБ стека.
▪️ Что это значит на практике
— Ограничение на количество потоков (~тысячи, не миллионы).
— Создание потока дорогая операция (~1ms).
— Context switch происходит в kernel space (затратно).
— Поэтому появились thread pools, чтобы переиспользовать потоки.
✔️ Плюсы
— Простая инфраструктура — один процесс использует все ядра.
— Shared memory между потоками (быстрый обмен данными).
❌ Минусы
— Race conditions, deadlocks, visibility/atomicity проблемы.
— Многопоточный код сложен в тестировании и отладке.
— Ограничение на количество потоков может стать узким местом даже при незагруженном CPU.
➡️ Модель 3: Virtual Threads / Goroutines (Java 21+, Go)
▪️ Суть: M:N mapping. Runtime сам мультиплексирует легковесные потоки на OS threads.
В Go это goroutines (управляются Go runtime через GMP-планировщик). В Java 21+ — Virtual Threads (Project Loom). Оба подхода реализуют концепцию green threads или user-level threads.
▪️ Механизм работы
Virtual Threads поверх ForkJoinPool.
— JVM создает carrier threads (platform threads).
— Виртуальные потоки привязываются/отвязываются от carrier threads.
— При блокирующей операции виртуальный поток отвязывается, carrier thread берет другой виртуальный поток.
— Стеки virtual threads хранятся в heap, управляются GC.
▪️Что это значит на практике
— Можно создавать миллионы потоков (в Go — goroutines, в Java — виртуальные потоки).
— Создание потока почти бесплатно (байты памяти вместо мегабайт).
— Блокирующий код работает эффективно — runtime просто переключает контекст на другую задачу.
— Планировщик делает принудительное переключение, предотвращая монополизацию CPU.
✔️ Плюсы
— Нет лимита на количество одновременных задач.
— Простой императивный код вместо async/reactive.
— Shared memory все еще доступна.
— Эффективное использование ресурсов.
❌ Минусы
— Проблемы многопоточности остаются (race conditions, deadlocks).
— В Java есть pinning проблема (synchronized блоки могут прибить virtual thread к carrier thread).
— Thread-local переменные нужно использовать осторожно.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
🎯 Перестань использовать new ArrayList<>() везде
❌ Было:
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
return names;
return List.of("Alice", "Bob", "Charlie");var names = new ArrayList<>(
List.of("Alice", "Bob", "Charlie")
);
👑 Магия IntelliJ IDEA: код без проекта
Нужно быстро протестировать Stream API, проверить регулярку или набросать алгоритм? Создавать временный класс в проекте — оверкилл. Для этого есть Scratch Files.
🔹 Что это
Временные файлы с полной поддержкой языка: подсветка, автокомплит, запуск кода. Живут в IDE, но не в проекте. Не попадают в Git, не захламляют структуру.
🔹 Как создать
— Ctrl+Shift+Alt+Insert → Scratch File.
— File → New → Scratch File.
— Или Ctrl+Shift+A → "New Scratch File".
🔹 Два типа
Scratch Files — файлы с конкретным языком (Java, Kotlin, SQL, JSON). Поддерживают автокомплит и выполнение.
Scratch Buffers — простой текст для заметок и TODO.
🔹 Зачем это нужно
— Тестируешь алгоритм без создания Test класса.
— Прототипируешь SQL перед добавлением в JPA.
— Сохраняешь сниппеты со Stack Overflow.
— Отлаживаешь регулярки, парсинг JSON, работу с датами.
Особенно полезно при рефакторинге: копируешь сложную логику в scratch, тестируешь варианты упрощения, не трогая основной код.
🔹 Фишки
— Автосохранение между перезапусками IDE.
— Запуск кода: Ctrl+Shift+F10 для Java/Kotlin.
— Все файлы в одном месте: Project view → Scratches and Consoles.
— Хранятся локально в ~/.config/JetBrains/, не в проекте.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
🐸 Библиотека джависта
#DevLife
✔️ Java-тест: Debouncer для частых событий
Напишите метод для production-кода 👇
📦 Задание
Реализуйте debouncer, который откладывает выполнение действия пока события продолжают поступать:
public class Debouncer {
public Debouncer(long delayMs) {
// Ваш код здесь
}
public void call(Runnable action) {
// Ваш код здесь
// Если вызов повторяется до истечения delayMs
// - отменить предыдущий и запланировать новый
// Выполнить только когда delayMs прошло без новых вызовов
}
}Debouncer debouncer = new Debouncer(300); // 300ms
debouncer.call(() -> search(query)); // откладываем
debouncer.call(() -> search(query)); // отменяем предыдущий
debouncer.call(() -> search(query)); // отменяем предыдущий
// Через 300ms выполнится только последний
Пятница, 19:00. Худшее время для деплоя, но идеальное, чтобы встроить LLM в архитектуру твоего Enterprise-проекта и заставить её работать с реальными данными.
Интеграция ИИ требует больше, чем просто вызов API. На открытом уроке обсудим, как обуздать нейронки на уровне системного проектирования.
Практическая часть занятия:
— RAG vs Fine-tuning: выбор стратегии для крупных проектов;
— инструменты: LangChain, векторные индексы и их роль в пайплайне;
— live coding: создание системы, отвечающей по базе документов.
Один из спикеров — Алексей Яндутов, ML-инженер в поиске Яндекса.
Урок предваряет курс «Разработка AI-агентов». Это техническое занятие для тех, кто планирует внедрять ИИ в реальные продукты.
Записаться на урок
🐸 Библиотека джависта
#DevLife
😮 Топ-вакансий для джавистов за неделю
Java Developer — офис (Новосибирск)
Java Developer — 230 000 — 240 000 ₽ — удалёнка
Java Developer — гибрид (Алматы)
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🔧 ObjectMapper и timezone: настройка обработки дат без указания зоны
При десериализации дат в формате "2024-01-15T10:00:00" без явной таймзоны Jackson по умолчанию использует UTC. Это может привести к неожиданным результатам при работе с ZonedDateTime или Instant, когда приложение работает в другой временной зоне.
🔵 Решение
▪️ Настройка ObjectMapper через Jackson2ObjectMapperBuilderCustomizer:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> builder
.timeZone(TimeZone.getDefault())
.featuresToDisable(
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
);
}
java.timeZone(TimeZone.getTimeZone("Europe/Moscow"))
🔬 Утечка, которую не видит heap dump
Интересная ловушка: вызываешь string.intern() на динамических строках, приложение падает с OOM, делаешь heap dump — а там всё чисто. Где утечка?
🔹 Суть проблемы
String Pool до Java 7 жил в PermGen, с Java 7 переехал в heap. Казалось бы, проблема решена. Но нет.
Внутри String Pool использует нативную хеш-таблицу StringTable, которая живёт в native memory (вне heap). Когда ты делаешь intern(), в heap создаётся сама строка, но ссылка на неё хранится в нативной StringTable.
🔹 Что происходит
Строки попадают в heap (GC их уберёт), но StringTable в native memory растёт бесконечно. Размер StringTable фиксирован и задаётся -XX:StringTableSize. При переполнении — коллизии, деградация, OOM.
🔹 Как увидеть?
bashjcmd <pid> VM.stringtable
bash-XX:NativeMemoryTracking=detail
jcmd <pid> VM.native_memory
🔧 Ускоряем Spring-приложение: кэш для @PathVariable и @RequestParam
В Spring MVC по умолчанию каждый запрос вызывает полный резолвинг аргументов методов контроллера через рефлексию. Но можно включить кэширование метаданных параметров через spring.mvc.argument-resolvers.cache-size.
Это особенно полезно при высоконагруженных API с большим количеством path/query параметров.
spring:
mvc:
argument-resolvers:
cache-size: 256
# Включает кэш для резолверов аргументов (PathVariable, RequestParam и т.д.)
# 256 — разумный размер для большинства приложений
System.out.println(«Final call»)
Завтра мы повышаем стоимость всех курсов. Успейте сегодня выделить память под развитие, пока прайс не совершил прыжок.
Выделить ресурсы под профессиональный рост
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
🖥 Kotlin + JPA = 💔 ?
Думаете, Kotlin идеально сочетается с JPA? А вот и нет!
data class, val, final-классы и даже дефолтные значения — всё это может тихо саботировать вашу персистентность.
ℹ️ В статье
→ Почему data-классы — плохая идея для entity
→ Как val ломает контракт JPA (но работает... пока)
→ Почему первичный ключ должен быть nullable
→ Как правильно настроить проект с плагинами no-arg и all-open
Не наступайте на грабли — читайте, пока не поздно
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
🐸 Библиотека джависта
#DevLife
AI-агенты в Enterprise: внедряем автономность в Java-стек
Корпорации активно переходят на AI-автоматизацию. Знание принципов работы агентов станет вашим преимуществом при проектировании сложных систем.
Сегодня в 19:00 МСК стартует курс «Углубленные AI-агенты».
Учебный план:
— мультиагентные системы для бизнес-задач;
— интеграция с базами данных и внешними API;
— проектирование надёжных и масштабируемых ИИ-решений;
— основы LLM архитектуры для архитекторов.
Стать AI-архитектором
Завтра стартуем: курс по разработке ИИ-агентов в Enterprise ☕
Хватит вручную прописывать логику под каждый запрос — внедряйте автономные системы. Мы научим проектировать агентные связки на CrewAI, управлять графами в LangGraph и интегрировать ИИ с вашим корпоративным стеком.
👉 Успейте занять место до начала занятий
Бэклог растёт, а ты всё ещё вручную «жаришь» бойлерплейт и промпты?
Это работа в забегаловке. Настоящий Шеф не сидит в отладке вечно — он проектирует Систему. ☕
В понедельник, 26 января, стартует интенсив по разработке ИИ-агентов. Мы научим создавать автономные архитектуры, которые закроют бизнес-задачи, пока ты занимаешься проектированием.
В программе:
— мультиагентные системы в CrewAI: делегирование рутины и контроль исполнения;
— сложная логика в LangGraph: управление состоянием в сложных графах;
— tool use интеграция: обучение агентов работе с твоим энтерпрайз-стеком. 🏗️
Записаться на курс
🔧 HikariCP: детектирование утечек соединений в production
При работе с базой данных через HikariCP нередка ситуация, когда Connection не закрывается должным образом (забытый close(), исключение до finally блока). В production это приводит к исчерпанию пула и падению приложения с ошибкой "Connection is not available".
🔹 Решение
▪️ Включение leak detection через application.yml
spring:
datasource:
hikari:
leak-detection-threshold: 30000
max-lifetime: 600000
connection-timeout: 20000
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
config.setLeakDetectionThreshold(30000); // 30 сек
config.setMaxLifetime(600000);
return new HikariDataSource(config);
}
🚀 Apache Kafka + Spring Boot Integration
Вместо синхронной архитектуры, вы получаете event-driven систему с миллионами сообщений в секунду и fault-tolerant обработкой.
Spring Kafka предоставляет production-ready инструментарий: транзакционную обработку сообщений с exactly-once семантикой, параллельную обработку через consumer groups, dead letter topic для failed messages, schema registry с Avro для контрактов, реактивную обработку с Project Reactor, автоматическую сериализацию и десериализацию.
📝 Промпт:
Implement production-grade Apache Kafka integration for Spring Boot 3 application:
— Configure Kafka connection: bootstrap servers (localhost:9092 or cluster), consumer/producer properties, SASL authentication (PLAIN, SCRAM-SHA-512), SSL/TLS encryption, ACKS configuration (all/1/0), compression (gzip, snappy, lz4), connection retry settings.
— Set up producer: KafkaTemplate with generic types, ProducerConfig with idempotence enabled, batching configuration (linger.ms, batch.size), send with callback for error handling, custom serializers (JsonSerializer, Avro), headers for metadata, partition selection strategy.
— Configure consumer: @KafkaListener annotation with topics, consumer groups for scalability, concurrency for parallel processing, manual commit mode (MANUAL, MANUAL_IMMEDIATE), error handling with ErrorHandler, SeekToCurrentErrorHandler for retry, RecordFilterStrategy for message filtering, batch listeners for bulk processing.
— Implement message patterns: fire-and-forget for async, request-reply with ReplyingKafkaTemplate, message correlation with correlation IDs, timeout handling, saga pattern for distributed transactions, outbox pattern for transactional messaging.
— Add dead letter topics: configure DeadLetterPublishingRecoverer, retention policies, separate DLT per topic, headers with exception info, retry count tracking, manual reprocessing endpoints, monitoring for DLT size.
— Configure Kafka Streams: StreamsBuilder for topology, KStream/KTable/GlobalKTable abstractions, stateful operations (aggregate, reduce), windowing (tumbling, hopping, session), joins (stream-stream, stream-table), interactive queries for state stores.
— Set up schema registry: Avro schema definitions, backward/forward compatibility checks, SchemaRegistryClient configuration, KafkaAvroSerializer/Deserializer, schema evolution strategies, versioning.
— Implement monitoring: consumer lag metrics with Burrow, JMX metrics export to Prometheus, Grafana dashboards for throughput/latency, alerting on lag/errors, Kafka Manager or AKHQ for UI, distributed tracing with Sleuth/Zipkin.
— Add testing: EmbeddedKafka for integration tests, Testcontainers with Kafka image, producer/consumer test utilities, await conditions for async verification, schema registry mock.
— Configure performance tuning: consumer fetch.min.bytes for batching, max.poll.records optimization, producer buffer.memory tuning, compression impact analysis, partitioning strategy for load balancing, retention and segment settings.
Deliverables: KafkaConfig.java, producer/consumer services, message DTOs with Avro schemas, error handling configuration, Kafka Streams topology, monitoring setup, integration tests, deployment manifests with resource limits
🔍 Просто о сложном: Pessimistic vs Optimistic Locking
Блокировки — способ контролировать одновременный доступ к данным. Два подхода: пессимистичный (блокируем заранее) и оптимистичный (проверяем при сохранении).
Простыми словами: пессимист говорит "займи очередь до конца", оптимист — "иди делай, потом проверим, не опередил ли кто-то".
🔹 Ключевые моменты
▪️ Pessimistic Lock — блокирует запись в БД на время транзакции (SELECT FOR UPDATE).
▪️ Optimistic Lock — проверяет версию при UPDATE, если изменилась — бросает исключение.
▪️ Пессимистичный подход безопаснее, но медленнее и может создавать deadlock'и.
▪️ Оптимистичный быстрее, но требует обработки конфликтов в коде.
▪️ В JPA: @Lock(PESSIMISTIC_WRITE) vs @Version.
🔹 Подводные камни
— Pessimistic lock держит соединение с БД — при долгих операциях можно исчерпать connection pool.
— Deadlock'и при неправильном порядке блокировок разных таблиц.
— Optimistic lock требует retry-логики на уровне приложения.
— @Version не работает с native queries — только через JPQL/Criteria.
— В высоконагруженных системах оптимистичные блокировки могут давать слишком много конфликтов.
✔️ Когда использовать Pessimistic
— Операции с деньгами, где конфликт недопустим.
— Высокая вероятность конкурентного доступа к одной записи.
— Критичные бизнес-процессы (бронирование последнего товара).
— Короткие транзакции с гарантией успеха.
✔️ Когда использовать Optimistic
— Низкая вероятность конфликтов (разные пользователи редко трогают одну запись).
— Долгие транзакции или работа через UI (пользователь открыл форму, долго думает).
— Микросервисная архитектура — меньше нагрузка на БД.
— Batch-операции, где можно переобработать failed записи.
🔧 Бонус-трюк: комбинируйте подходы. Например, optimistic lock для UI-операций (пользователь редактирует профиль) + pessimistic для критичных API endpoints (списание средств). В одном приложении могут жить оба паттерна.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Enterprise AI: внедрение RAG в Java-экосистему
23 января в 19:00 на открытом уроке к курсу «Разработка ИИ агентов» разберём, как научить LLM работать с корпоративными знаниями без утечек и ошибок. Обсудим архитектуры RAG и методы Fine-tuning для реализации сложных Enterprise-решений.
Спикер — Игорь Стурейко, тимлид в «Газпроме» и AI-архитектор на Kubernetes. В видеосообщении Игорь делится опытом построения агентных систем и рассказывает, что ждёт студентов на курсе подготовки архитекторов ИИ.
На уроке разберём:
— принципы работы Retrieval-Augmented Generation в закрытом контуре;
— обзор инструментов для интеграции LLM в промышленный стек;
— работу с векторными индексами (FAISS, Chroma) для быстрого поиска.
📅 Когда: 23.01 в 19:00 МСК
Узнать подробности
🐸 Библиотека джависта
#DevLife
❓ Можно ли переопределить статический метод?
Нет, статические методы не переопределяются (override), они скрываются (hide).
При вызове статического метода решение о том, какой метод выполнить, принимается на этапе компиляции по типу ссылки, а не по типу объекта.
class Parent {
static void test() { System.out.println("Parent"); }
}
class Child extends Parent {
static void test() { System.out.println("Child"); }
}
Parent obj = new Child();
obj.test(); // Выведет "Parent"
🐸 Библиотека джависта
#DevLife
👑 Магия IntelliJ IDEA: Structural Search & Replace
Рефакторишь проект, нужно найти все места, где используется deprecated метод с определённым паттерном вызова. Ctrl+F не поможет — он ищет текст, а не структуру кода. Для этого есть SSR.
🔹 Что это
Structural Search — поиск по AST-дереву кода, а не по тексту. Ищешь паттерны: методы с конкретными параметрами, переменные определённого типа, цепочки вызовов. И сразу заменяешь на новый код.
🔹 Как открыть
— Ctrl+Shift+A → "Structural Search" или "Structural Replace".
— Edit → Find → Search/Replace Structurally.
— Или Ctrl+Shift+F → переключись на вкладку "Structural".
🔹 Готовые шаблоны
IDEA поставляется с десятками шаблонов:
— Existing templates → Java → видишь примеры для логирования, коллекций, исключений.
— Можешь скопировать и доработать под себя.
🔹 Зачем это нужно
— Рефакторинг legacy за минуты вместо часов.
— Находишь bug patterns (например, забытые null-checks).
— Автоматизируешь code review — проверяй стандарты кода.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
❓ Structured Concurrency API — кто-то юзает в проде?
Наш подписчик спрашивает:
Перешли на Java 21, Virtual Threads зашли отлично. Теперь смотрю на Structured Concurrency API (JEP 462, пока в preview).
У нас классика: один запрос → параллельно дергаем несколько микросервисов → агрегируем ответ. Structured Concurrency пока preview feature. Стоит ли уже переходить или рано?