MiddleJava Developer > Java Core > Multithreading
Короткий ответ Синхронизированные коллекции — это обёртки над обычными коллекциями, создаваемые через Collections.synchronizedList(), synchronizedMap() и т. п., а также исторические Vector и Hashtable: в них каждый публичный метод синхронизирован целиком, все операции захватывают один общий монитор коллекции. Concurrent-коллекции из java.util.concurrent (ConcurrentHashMap, CopyOnWriteArrayList и др.) спроектированы для высокой конкуренции: они используют гранулярную синхронизацию, CAS и слабо консистентные итераторы. Как это работает подробнее Synchronized-коллекции гарантируют потокобезопасность, но создают сильную конкуренцию: чем больше потоков обращается одновременно, тем больше времени они проводят в ожидании общей блокировки, поэтому масштабируемость плохая. Итерироваться по ним нужно внутри собственного блока synchronized, иначе поведение при параллельном изменении недетерминировано. ConcurrentHashMap в современных версиях синхронизирует доступ по корзинам таблицы: операции над разными корзинами не меш
concurrentcopyonwritearraylist
MiddleJava Developer > Java Core > Multithreading
Короткий ответ Синхронизированный нестатический метод захватывает монитор экземпляра this на всё время выполнения всего метода; статический синхронизированный метод блокирует монитор объекта класса (SomeClass.class). synchronized-блок позволяет указать, какой объект использовать как монитор, и ограничить синхронизацию только нужным фрагментом кода. Как это работает подробнее Пока поток внутри synchronized-метода на this, другой поток не сможет войти ни в один другой synchronized-метод того же объекта. Статические методы синхронизируются между собой на объекте Class, поэтому говорят про «класс-лок» в отличие от «объект-лока». Блок уменьшает время удержания блокировки и снижает конкуренцию (contention), поэтому считается более гибким и, как правило, более производительным: остальной код метода выполняется без блокировки. Монитор в Java реентерабелен: поток, уже владеющий монитором, может повторно войти в синхронизированный код по тому же объекту без взаимной блокировки самого себя. Пример кода Что использовать
javalock
SeniorJava Developer > Java Core > Multithreading
Короткий ответ volatile решает проблему видимости: чтение и запись volatile-переменной выполняются напрямую из основной памяти, а между записью одним потоком и чтением другим устанавливается отношение happens-before. Однако volatile не обеспечивает атомарность: составная операция «прочитать — изменить — записать» вроде counter++ остаётся неатомарной. Атомарные классы из java.util.concurrent.atomic дают атомарные операции без блокировок — на базе аппаратной инструкции CAS. Как это работает подробнее volatile идеален для флагов состояния вроде boolean running, которые один поток выставляет, а другой читает. При counter++ два потока могут одновременно прочитать старое значение и записать результат, «потеряв» одно из увеличений, — даже если поле объявлено volatile. Атомарные классы AtomicInteger, AtomicLong, AtomicReference предоставляют методы getAndIncrement(), addAndGet(), compareAndSet(expected, newValue), реализованные на аппаратной инструкции CAS (Compare-And-Swap). CAS действует оптимистично: compareAndSet
atomiccas
SeniorPython Developer > Основы Python > Веб-фреймворки: Django, Flask, FastAPI
Короткий ответ WSGI и ASGI — это интерфейсы, которые позволяют Python-веб-приложениям общаться с веб-серверами. WSGI спроектирован для синхронных приложений, а ASGI дополнительно поддерживает асинхронный код, WebSocket и конкурентную обработку множества соединений. Как это работает подробнее Выбор интерфейса влияет на сервер и архитектуру приложения. WSGI. Web Server Gateway Interface традиционно используется при развёртывании Django и подходит для приложений без асинхронной обработки запросов. ASGI. Asynchronous Server Gateway Interface поддерживает синхронные и асинхронные приложения, включая асинхронные представления Django. Соединения. ASGI допускает долгоживущие соединения, например WebSocket, и асинхронные рабочие процессы. Серверы. Для WSGI используют Gunicorn и uWSGI, для ASGI — Uvicorn и Daphne. Обработка. WSGI обрабатывает каждый запрос синхронно, а ASGI позволяет обрабатывать множество соединений конкурентно. Что использовать на практике Классический Django. Для синхронного приложения оставайся на
asgideployment
JuniorJava Developer > Java Core > Основы Java
Короткий ответ Java — строго pass-by-value. При вызове метода создаётся копия значения аргумента. Для примитивных типов копируется само значение, для ссылочных — копия ссылки на тот же объект. Поэтому изменения состояния объекта внутри метода видны снаружи, а переприсваивание параметра — нет. Как это работает подробнее Разница между передачей по ссылке (как в C++) и по значению проявляется в двух типовых сценариях. Примитивный аргумент. Изменение параметра внутри метода никак не влияет на переменную в вызывающем коде: метод работает с копией значения. Ссылочный аргумент. По значению передаётся копия ссылки, но объект тот же самый: вызов list.add(...) или изменение поля будет видно снаружи. Переприсваивание. Если внутри метода выполнить param = new Something(), изменится только локальная копия ссылки, а исходная переменная продолжит указывать на прежний объект. Пример кода Что использовать на практике Помнить, что классический «обмен значений двух переменных» через метод в Java не работает — меняются лишь копи
javamethods
MiddleJava Developer > Java Core > Исключения
Короткий ответ Да, такое возможно. Блок finally не выполнится, если JVM завершается до выхода из try — при вызове System.exit() или аварийном завершении (сбой JVM, OutOfMemoryError, kill процесса), — либо если поток застревает внутри try (бесконечный цикл, вечное ожидание на мониторе) и просто не доходит до блока. Как это работает подробнее finally гарантированно выполняется при обычном завершении try, при исключении и даже перед return — управление передаётся в finally до выхода из метода. Это ключевая гарантия языка. Блок не выполняется только тогда, когда завершается сама JVM или поток не может выйти из try. System.exit() — завершает виртуальную машину, выполнение до finally не доходит. Аварийное завершение — сбой JVM, критическая ошибка вроде OutOfMemoryError, принудительное завершение процесса (kill). Застревание потока — бесконечный цикл или вечное ожидание на мониторе внутри try: код не доходит до finally; в старых версиях к этому приводила и принудительная остановка потока Thread.stop(). Пример кода Ч
control-flowexceptions
MiddleJava Developer > Java Core > ООП
Короткий ответ Полиморфизм (дословно «много форм») — принцип ООП, при котором одно и то же имя метода (или один и тот же код) работает с объектами разных типов, проявляя себя по-разному. В Java различают два вида: полиморфизм времени компиляции — перегрузка методов, и полиморфизм времени выполнения — переопределение методов, который называют также динамической диспетчеризацией. Как это работает подробнее Механизм runtime-полиморфизма: переменная имеет тип родительского класса, а указывает на объект наследника. При вызове переопределённого метода JVM определяет фактический тип объекта во время выполнения и вызывает реализацию именно этого класса. Перегрузка (overloading). В одном классе несколько методов с одинаковым именем и разными параметрами; нужный вариант выбирает компилятор по типам переданных аргументов. Переопределение (overriding). Наследник заменяет реализацию унаследованного метода, сохраняя сигнатуру; выбор реализации происходит на этапе выполнения. Практический эффект. Один метод, принимающий Ani
javaoop
SeniorPython Developer > Основы Python > Многопоточность и асинхронность
Короткий ответ async и await применяются для неблокирующего кода там, где много ожидания: внешние API, файловые операции, сетевые запросы. Их не стоит использовать для вычислительных задач и простых программ без длительных ожиданий — выигрыша не будет. Как это работает подробнее В отличие от синхронного кода, где программа стоит на каждом ожидании, асинхронная программа работает в одном потоке и кооперативно переключает задачи в точках await. Кооперативность. Переключение происходит только в точках await, поэтому нет блокировок и гонок за общие данные, характерных для потоков. Масштаб. Один поток обслуживает тысячи одновременных соединений, пока корутины ждут внешние ресурсы. CPU-bound задачи. asyncio их не ускоряет: вычисления выполняются тем же процессором, поэтому нужны multiprocessing или потоки. Архитектура. Внутри обычной синхронной функции корутину не запустить: нужен await или asyncio.run(), поэтому асинхронность продумывают заранее. Пример кода Что использовать на практике Выбор механизма. Для I/O-bo
asyncawait
MiddlePython Developer > Основы Python > Декораторы
Короткий ответ functools.wraps — декоратор из стандартного модуля functools, который применяется к функции-обёртке внутри декоратора. Он копирует обёртке метаданные декорируемой функции, чтобы она сохраняла её имя, документацию и другие атрибуты. Как это работает подробнее Проблема. Без wraps обёртка затирает метаданные: имя функции становится wrapper, пропадают __doc__, __module__ и другие атрибуты. Последствия. В стектрейсах и ошибках фигурирует внутренняя обёртка вместо реальной функции, что ломает интроспекцию, документаторы и инструменты. Решение. @wraps(func) копирует обёртке атрибуты декорируемой функции и обновляет её словарь __dict__, поэтому обёртка «выдаёт себя» за исходную функцию. Правило. Хорошим тоном считается всегда оборачивать wrapper в @wraps(func) при написании собственных декораторов. Пример кода Что использовать на практике Каждый декоратор. Применяй @wraps(func) к обёртке во всех собственных декораторах — это просто и безопасно. Отладка. Сохранённые __name__ и __doc__ делают стектрейсы,
decoratorsfunctools
MiddleJava Developer > Java Core > Сборка мусора
Короткий ответ Сборка мусора — автоматический процесс управления памятью: JVM сама находит объекты в куче, до которых нельзя добраться по цепочке ссылок от корневых точек (корней), и освобождает их память. Программисту не нужно вручную удалять объекты, как через free или delete в C/C++. Как это работает подробнее Базовый алгоритм — mark-and-sweep: на первом шаге GC обходит граф объектов от корней и помечает достижимые, на втором удаляет непомеченные. В современных HotSpot JVM куча разделена на поколения: молодые объекты «умирают» быстро, для них применяется копирующая сборка с частыми небольшими паузами, а выжившие со временем переходят в старое поколение, где работают другие алгоритмы. Корни (GC roots) — локальные переменные активных потоков, статические поля и другие точки входа в граф объектов. Достижимость — объект жив, пока до него можно добраться от корней; недостижимые объекты удаляются. Поколения — young и old generation: для молодых объектов частая копирующая сборка, для старых — отдельные стратегии.
gcheap