Вопросы к собеседованию Java-backend, Java core (60 вопросов)
Добрый день! Представляю вашему вниманию список вопросов к собеседованию Java Backend, которые я оформлял на протяжении около 2х лет.
Вопросы разбиты по темам: core, collections, concurrency, io, exceptions, которые задают основные направления хода технического собеседования. Звездочками отмечен субъективный (с точки зрения автора) уровень сложности вопроса, в сноске спойлера — краткий ответ на вопрос. Ответ представляет для интервьювера правильное направления развития мысли кандидата.
Опросник не претендует на роль исчерпывающего средства оценки технических навыков кандидата, это скорее еще одна компиляция вопросов и тем по Java и сопуствующим технологиям, принципам и концепциям разработки, коих в сети десятки. Она преследует цель собрать большое число технических вопросов, возникающих на собеседованиях, в удобном для читателей Хабра формате. Некоторые ответы следует воспринимать как мнемоники, «размечивающие» пространство поиска, так что глубже копать нужно уже в документации.
Также не стоит обращать внимание на слишком большое кол-во списков, так как это все-таки не вольное переложение авторских знаний с примесью литературной экспреcсии (что на хабре котируется и собирает аудиторию, особенно в пятницу). Этот список я составил для самого себя как способ структурировать основные тематики и типичные вопросы с собеседований, так что все дополнения и правки только приветствуются.
Это также не руководство к действию — не надо закидывать бедных кандидатов всеми вопросами из списка.
Секция Core:
- Назвать методы Object [1]. (*)
Краткий ответ
- toString()
- equals()
- hashCode()
- wait()
- notify()
- notifyAll()
- finalize() — deprecated в Java 9+
- getClass()
Про toString(), equals(), hashCode() и их контракт знать нужно обязательно
- Что такое string-pool? В чем отличие cоздания строки через new от литерала? Что такое String.intern()? (*)
Краткий ответ
string-pool — структура в памяти, хранящая массив всех строк-литералов программы.
String.intern(), соотвественно, вернет строку из пула, при наличии таковой. Полезно при сравнениях вида:
new String("hello").intern() == new String("hello").intern()
Т.к без интернирования пришлось бы сравнивать строки через equals, что может быть медленнее при наличии длинных строк. В данном случае возвращается ссылка на один и тот же объект строки из пула, и проверка проходит с true.
- Почему хранить пароль предпочтительнее в char[]/byte[], а не в String [2]? (**)
Краткий ответ
- Строка в виде литерала сразу раскрывает пароль, плюс она всегда хранится в string-пуле
- byte[]/char[] возможно сбросить после использования, и удалить все ссылки на него
- Привести пример плохой реализации hashCode() (*)
Краткий ответ
Метод, возвращающий константу, или значения хэшкодов с неравномерным распределением, приводящим к коллизиям
- Примитивы, врапперы. Package/unpackage (boxing/unboxing). (*)
Краткий ответ
- Типы примитивы не создаются в куче, их жизненный цикл ограничен жизненным циклом стек-фрейма
- Package — создание типа-обертки в хипе для аналогичного типа-примитива, например при объявлении аргумента как Integer, и при передаче int в качестве аргумента. Unpackage — обратная операция
- Сравнение по == и по equals (*)
Краткий ответ
- Сравнение по "==" — сравнение по ссылкам
- Сравнение по «equals» — если переопределен equals, то это сравнение эквивалентности объектов по их полям, если нет — по ссылкам на объекты
- Свойства, которым должен удовлетворять equals (**)
Краткий ответ
- Рефлексивность: a==a
- Симметричность: a==b, b==a
- Транзитивность: a==b, b==c, a==c
- Консистентность: Множественные вызовы equals должны возвращать один и тот же результат
- Отличия String/StringBuilder/StringBuffer (**)
Краткий ответ
- String [2] — иммутабельный байтовый массив
- StringBuilder [3] — helper-класс для построения строк, не предоставляет гарантий синхронизации
- StringBuffer [4] — то же, что и StringBuilder, с synchronized методами
- Приведите пример нарушения симметрии equals (**)
Краткий ответ
- Создать класс Point2D c полями x,y: double
- Унаследовать от него класс ColoredPoint2D c доп. полем color
- a: Point2D
- b: ColoredPoint2D
- a.equals(b), !b.equals(a)
- Interface vs Abstract Class. (*)
Краткий ответ
- Интерфейс есть средство наследования API, абстрактный класс — средство наследования реализации
- Через интерфейсы возможно осуществлять множественное наследование, абстрактный класс можно наследовать в одном экземпляре.
- В интерфейсе нет возможности определить поля и конструкторы
- override vs overload (*)
Краткий ответ
- override — возможность переопределениия поведения метода в типах-потомках
- overload — возможность переопределять метод с одним именем, но разным набором аргументов
- Как в Java сделать утечку памяти? (**)
Краткий ответ
- Используя самописный класс стека, при выполнении операции pop() не присваивать предыдущей ссылке значение null.
- Также можно неверно использовать HashMap [5] вместо WeakHashMap [6] для кэширования чего-нибудь большого, например картинок ваших товаров, пользователей и.т.д в. Т.к ссылки на ключи сильные (strong references), значения по этим ключам будут висеть в хипе до
морковкиного заговенья следующей перезагрузки jvm процесса или удаления ключа из мапы и обнуления ссылки на него. Вообще, кэширование — тема для отдельного разговора
- Также, статья [7] (но староватая)
- Как вернуть псевдо-случайную последовательность целых чисел/чисел с плавающей запятой? (**)
- В чем проблемы Random [8]? (**)
Краткий ответ
Random [8] возвращает псевдо-случайную числовую последовательность, основанную на линейном конгруэнтном методе и seed'е, основанном на timestamp'е создания
j.u.Random.
Соотвественно, зная время создания, можно предсказать такую последовательность. Такой генератор является детерминированным, и криптографически нестойким. Для исправления этого лучше использовать
SecureRandom [9]
- GC и различные его виды в JVM. Какой объект считать достижимым. Как происходит сборка мусора (своими словами).(**)
Краткий ответ
Виды GC:
- Serial Stop the World
- Parallel
- CMS (В чем недостаток по сравнению с Parallel?)
- G1 (Назвать отличие от CMS)
- Shenandoah
Если объект является достижимым из стека или статической области, то он не поддается сборке мусора
- Java 8: стримы, функциональные интерфейсы, Optional [10] (**)
Краткий ответ
Stream [11] — интерфейс, предоставляющий функциональные возможности обработки коллекций (filter, map, reduce, peek)
Операции на стримах делятся на терминальные и нетерминальные. Нетерминальные операции модифицируют pipeline операций над коллекцией, при этом не изменяя саму коллекцию, терминальные (например, collect) — проводят действия pipeline'а, возвращают результат и закрывают
Stream [11].
FunctionalInterface [12] — аннотация, предоставляющая возможность использовать лямбды на месте интерфейсов (например, при передаче лямбды в качестве аргумента в метод)
Optional [10] — интерфейс, предохраняющий пользовательский код от nullable ссылок. Оборачивает исходный nullable объект, и предоставляет возможность понять, хранит ли non-nullable объект или нет.
- Java 8: Что такое capturing/non-capturing lambda (**)
Краткий ответ
- capturing lambda захватывает локальные переменные/аргументы/поля объекта из внешнего скоупа
- non-capturing lambda — не захватывает контекст внешнего скоупа, не инстанцируется каждый раз при использовании
- Новые возможности Java 9 — 11 (**)
Краткий ответ
- Новые методы в String
- Java 9: Модульность
- Java 9: Методы в Objects: requireNonNullElse() и requireNonNullElseGet()
- Java 9: List.of(), Set.of(), Map.of(), Map.ofEntries()
- Java 9: Optional.ifPresentOrElse(), Optional.stream()
- Java 10: var type-inference
- Java 11: Files.readString(), Files.writeString()
- Java 11: Local-Variable Syntax for Lambda Parameters — выведение типов у var-аргументов в лямбда-параметрах
- Java 11: JEP 321: HTTP Client
Можно как бонус назвать какие-нибудь:
- JEP 328: Flight Recorder
- JEP 335: Deprecate the Nashorn JavaScript Engine
- JEP 320: Remove the Java EE and CORBA Modules
но это совершенно необязательно, покажет лишь вашу въедливость при чтении JDK'шных Release Notes :)
- Swing: рассказать про EDT, как им пользоваться (**)
Краткий ответ
EDT — тред в котором производится обработка пользовательских действий на UI: движение курсора, нажатие клавиш, скролл, drag'n'drop и.т.д. Соотвественно, все «тяжелые» по времени и ресурсам операции нужно выносить в отдельный worker-тред (
SwingUtils.invokeLater(...)
), чтобы не фризить EDT.
- Swing: перечислить все виды Layout, которые знаете (**)
- Generics: В чем преимущество, как работают? Что такое type-erasure? В чем отличие от шаблонов C++? (**)
Краткий ответ
- Типы дженерики обеспечивают параметрический полиморфизм, т.е выполнение идентичного кода для различных типов. Типичный пример — коллекции, итераторы
- type-erasure — это стирание информации о типе-параметре в runtime. Таким образом, в байт-коде мы увидим List, Set вместо List<Integer>, Set<Integer>, ну и type-cast'ы при необходимости
- В отличие от дженериков в Java, в С++ шаблоны в итоге приводят к компиляции метода или типа для каждого специфицированного типа параметра (специализация шаблона). Да простят меня здесь адепты С++.
- Generics: Метод принимает ссылку на List<Parent>. Child наследуется от Parent. Можно ли в метод передать List<Child>? (**)
Краткий ответ
В типе аргумента нужно указать List<? extends Parent>
- Generics: Ковариантность/контравариантность. Спросить про принцип PECS как бонус
Краткий ответ
- Ковариантность — List<? extends T>, если B extends T, то и List<B> extends List<T>
- Контраваринтность — List<? super T>, если B super T, то и List<B> super List<T>
- PECS — Producer-Extends-Consumer-Super, метод отдаёт ковариантный тип, принимает контравариантный (прим. автора — последнее интуитивно не очень понятно)
- Регионы памяти в JVM (**)
Краткий ответ
Java 8: Metaspace, Old Generation, Young Generation (Eden Space/Survivor Space), Stack, Constant Pool, Code Cache, GC Area.
- Hard-references, weak references, soft-references, phantom-references (***)
Краткий ответ
- Hard-references — стандартные ссылки на объекты, которые становится eligible for collection после недостижимости из root set
- Weak-references — объекты могут быть удалены при наличии слабой ссылки на него в любое время
- Soft-references — объекты могут удалятся GC при недостатке памяти
- Phantom-references — объекты не доступны напрямую по ссылкам, перед удалением помещаются в очередь на удаление. Нужны для более безопасной финализации ссылок (вместо finalize)
- Рассказать про classloader'ы и их иерархию. Из за чего, например, может возникать NoClassDefFoundError, NoSuchMethodError? (***)
Краткий ответ
Иерархия classloader'ов
- Bootstrap
- System
- Application
- NoClassDefFoundError [17] может возникнуть, если нужной библиотеки с этим классом нет в classpath
- NoSuchMethodError [18] может возникнуть из-за несовместимости ваших библиотек, если зависимая библиотека A вызывает метод из старой версии библиотеки B, но в classpath есть более новая версия библиотеки B, c другой сигнатурой этого метода
- Какими способами можно сконструировать объект в Java? (**)
Краткий ответ
- Через конструктор
- Через статический factory-method
- Через паттерн Builder
- Как идентифицируется класс в Java? (**)
Краткий ответ
По его
FQDN и classloader'у
- Bytecode: назовите какие-нибудь инструкции и опишите их (**).
Краткий ответ
Здесь только краткий список команд:
* Попросить описать принцип действия стековой машины, как бонус. Допустим, на примере вызова метода.
- Bytecode: invokevirtual, invokestatic, invokespecial — когда используются?
Краткий ответ
- invokevirtual — вызовы методов (в Java все методы виртуальные)
- invokestatic — вызовы статических методов
- invokespecial — вызовы конструкторов и приватных методов
Секция Concurrency:
- synchronized. wait/notify/notifyAll. Как есть примитивы аналоги из пакета j.u.c? (**)
Краткий ответ
Дальше тезисы:
- synchronized — ключевое слово, обозначающее скоуп критической секции. Можно ставить напротив объявления метода, или в виде блока в коде.
- wait() — ожидание треда до тех пор, пока он не будет разбужен другим тредом через notify/notifyAll.
- У wait() есть перегруженные версии с таймаутами.
- Тред ставится в wait-set на объекте
- Перед вызовом wait() нужно захватить монитор на данном объекте (через synchronized)
- Магия wait() — он отпускает лок на мониторе объекта после вызова, так чтобы в дальнейшем другой тред мог захватить монитор и вызвать notify/notifyAll
- notify() — будит один из ожидающих тредов, но Важно! — лок на объекте не отпускает, т.е ожидающий тред разбужен будет, но с ожиданием входа в критическую секцию объекта (т.к как будто остановился на synchronized). Так что если после notify есть тяжелые операции, это затормозит ожидающий тред, т.к тред с notify еще не отпустил монитор
- notifyAll() — будут разбужены все треды в wait-set, но при этом далее между тредами происходит contention («сражение») за монитор
- Тред на wait() может быть разбужен также через interrupt, или через spurious wake-up, или по таймауту
- Так что условие выполнения, которого ожидает тред, проверяется в цикле while, а не в if
- Примитив-аналог — Condition [19]
- volatile. happens-before. (**)
Краткий ответ
- Ключевое слово volatile устанавливает отношение happens-before над операциями записи-чтения на поле
- Таким образом, операции чтения из читающих тредов будут видеть эффекты записи пишущих тредов.
- В частности, решается проблема double checked locking. Для double/long типов есть проблема атомарности, она решается через атомики
- AtomicInteger, AtomicLong, AtomicBoolean, AtomicDouble (**)
Краткий ответ
- Атомики предоставляют возможность изменения переменной в нескольких потоках без эффекта гонок.
- Например, 10 тредов инкрементят AtomicInt = 0, основной тред ждет их выполнения через countdown-latch, далее проверка атомика должна показать 10.
- Основной механизм под капотом атомиков — цикл cas (compare-and-set). На примере increment:
- Читаем старое значение
- Перед set'ом проверяем старое значение, если оно не изменилось, сетаем старое + 1
- Если изменилось, в след. итерации получаем «новое» старое, далее см. п. 1
- Редкий вопрос — как поймать exception из другого треда? (***)
- ReentrantLock [21] (**)
Краткий ответ
Примитив синхронизации, с помощью которого можно установить границы критической секции. Тред, перед входом в критическую секцию должен сделать захват c операцией
lock()
, после выхода из крит. секции — сделать
unlock()
. Другой тред в это время ожидает на lock'е (можно указывать таймаут ожидания), либо может проверить доступность через
tryLock()
.
ReentrantLock [21] обязательно нужно освобождать (такое кол-во раз, сколько раз он был захвачен), в противном случае будет thread starvation у других тредов, ожидающих у границы критической секции.
ReentrantLock [21] может быть «честным» (fairness = true), тогда приоритет отдается тредам, ждущих на нем наибольшее кол-во времени, но это вроде как уменьшает производительность
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
- Countdown Latch [22]/Cyclic Barrier [23] (**)
Краткий ответ
CountdownLatch («защелка») — примитив синхронизации, с помощью которого, например, основной thread может ожидать выполнения работы остальных N тредов. Треды, выполняющие работу, выполняют countDown() на защелке, основной тред ожидает на операции await(). Когда счетчик достигает нуля, основной тред продолжает работу.
Для синхронизации N тредов (все ждут всех) и переиспользования используется CyclicBarrier [23], ему также можно указывать действие (через Runnable), выполняемое после синхронизации всех-со-всеми
- ThreadLocal [24] (**)
Краткий ответ
Класс, предоставляющий доступ к операциям get/set в области видимости треда. Под капотом содержит кастомную реализацию мапы со слабыми ссылками на ключи-треды. Каждый тред имеет доступ только к своим данным.
- Создание singleton? (**)
Краткий ответ
- Наивным способом, с проверкой на null статического поля
- Double checked locking [25] (объяснить проблемы double checked locking)
- Простой — инициализация статического поля, или через enum, т.к ленивая инициализация thread-safe по-умолчанию
- Способы запустить поток? (***)
Краткий ответ
- Переопределить Thread#run(), запустить через Thread#start()
- new Thread(Runnable).start()
- Через ExecutorService [26], используя utility-класс Executors [27]
- ConcurrentHashMap [28] (**)
Краткий ответ
ConcurrentHashMap [28] имеет разные реализации в 1.7 и 1.8 (что стало для меня неожиданностью).
Раньше параллелизм основывался на идее сегментирования хэштаблицы на основе заданного уровня параллелизма.
Начиная с Java 8 — это единый массив бакетов с lock-free (локинг на первой ноде бакета с cas-циклом) и конкурентным ресайзингом.
Частичная реализация ConcHashMap (аля Java 8) с нуля [29] от
kuptservol [30]
- ConcurrentSkipListMap [31]
Краткий ответ
Lock-free структура данных, хранящая упорядоченный набор элементов, с O(log N) временем доступа/удаления/вставки и weakly-consistent итераторами. Под капотом содержит структуру SkipList, предоставляющую собой слои связных списков, от верхнего к нижнему, элементы верхнего списка ссылаются на элементы нижнего списка под ними. Вероятность попадания элемента при вставке в самый нижний список — 1.0, далее она равняется p (либо 1/2, либо 1/4 как правило) — вероятности попадания элемента из нижнего списка в верхний. Таким образом, на самом верхнем будет вставлено минимальное кол-во элементов. Skiplist — вероятностная структура данных. Подробнее и доходчиво про skiplist описано
здесь [32]. Полезна, если стоит задача отсортировать поток событий, одновременно читаемый несколькими тредами, которым нужно делать срез по временному интервалу. Более медленные операции по сравнению с
ConcurrentHashMap [28]
- Thread states (**)
Краткий ответ
- NEW
- RUNNABLE
- BLOCKED(monitor lock)
- WAITING(Thread.join)
- TERMINATED
- Deadlocks, условия наступления, как избежать: (***)
Краткий ответ
- Условия наступления — эксклюзивность доступа к ресурсам, наличие циклов в графе ожиданий ресурсов, отсуствие таймаутов на ожидание
- Как избежать — задать порядок доступа к ресурсам. Всегда обращение в порядке либо Thread1->Thread2, либо Thread2->Thread1
- ThreadPoolExecutor [33] — описать механизм работы, св-ва, частности (fixed threadpool, scheduled, single thread executor) (***)
Краткий ответ
ThreadPoolExecutor [33] — средство контроля исполнения параллельных задач, задействует один из свободных тредов в общем пуле, или ставит задание в очередь, если таковых нет, или достигнуты определенные условия (ниже)
Основными св-вами ThreadPoolExecutor [33] являются corePoolSize и maxPoolSize. Если текущее количество тредов в пуле < corePoolSize — новый тред будет создаваться в независимости от того, есть ли в пуле незанятые треды. В промежутке между corePoolSize и maxPoolSize тред будет создаваться в том случае, если заполнена очередь задач, и удаляться спустя keepAliveTime. Если кол-во тредов стало >= maxPoolSize — новые треды не создаются, а задачи ставятся в очередь.
Есть возможность регулировать поведение очереди:
- Direct handoffs: немедленная передача задачи тредпулу. Нет понятия очереди задачи. Если свободных тредов нет — кидается exception. Применимо при неограниченных maxPoolSize, но нужно понимать проблему при быстрых записях и медленных чтениях, что может спровоцировать непомерное потребление ресурсов
- Unbounded queues: очередь без ограничений. Задачи будут добавляться в нее при превышении corePoolSize, при этом maxPoolSize будет игнорироваться. Unbounded queues имеют проблемы потребления ресурсов при больших нагрузках, но сглаживают рост тредов при пиках.
- Bounded queues: очередь с ограничениями. Задачи будут добавляться в очередь до достижения некоего capacity. Для достижения наилучшей производительности нужно понимать размеры corePoolSize и самой очереди и чем можно пожертвовать — перфомансом (малый corePoolSize и большая очередь), или же памятью (ограниченная очередь, большой corePoolSize)
Частности ThreadPoolExecutor [33]:
- ScheduleThreadPoolExecutor [34] — применяется для периодичных по времени задач
- fixed thread pool — частность ScheduleThreadPoolExecutor'а [33] с настроенным corePoolSize и unbounded queue
- single thread executor — тредпулл, c сorePoolSize = 1, гарантирующий последовательное выполнение задач из очереди
Секция Collections:
- Рассказать про java.util.collection. (*)
Краткий ответ
- Iterable [35] — реализуют коллекции, по которым можно проитерироваться
- Сollection [36] — общий интерфейс для коллекций
- List [37] (стандартная реализация ArrayList [38]) — список с массивом элементов, с возможностью случайного доступа элемента по индексу за O(1), вставкой/удалением со сложностью O(n)
- Set [39] (стандартная реализация HashSet [40]) — мн-во элементов без дубликатов. Нет возможности доступа по индексу, есть вставка и удаление за O(1)
- Map [41] (стандартная реализация HashMap [5]) — мн-во пар элементов «ключ-значение». Доступ по ключу/добавление/удаление за O(1) при оптимальном случае, O(n) — при вырожденном
Обзор по коллекциям от JournalDev [42]
- Устройство ArrayList [38], LinkedList [43], HashMap [5], HashSet [40]. Когда следует использовать. Контракт equals/hashcode для Map, Set (*)
Краткий ответ
Обзор по коллекциям от
JournalDev [42]
- Итератор по коллекции, его св-ва и интерфейс (*)
Краткий ответ
- Может только один раз проходить по коллекции. Для прохождения в двух направлениях есть ListIterator [44]
- Если в foreach цикле структурно модифицировать коллекцию, при последующем обращению к элементу (неявно через итератор) получим ConcurrentModificationException [45] (fail-fast)
- hasNext(), next() — основные методы
- Hashtable [46] vs HashMap [5] (*)
Краткий ответ
- Hashtable [46] — legacy, thread safe, методы синхронизированы, поэтому работа с Hashtable (обращение, удаление, добавление) в целом накладнее
- HashMap [5] — не thread-safe
- Java 8,11: новые методы в Map (**)
Краткий ответ
- Java 8: compute
- Java 8: computeIfAbsent
- Java 8: computeIfPresent
- Java 8: forEach
- Java 8: putIfAbsent
- Java 11: factory-методы of()
- LinkedHashMap [47], зачем он нужен (**)
Краткий ответ
- Позволяет сохранять порядок вставки пар key-value в Map
- Каждый entry содержит помимо hash, value, next (следующий элемент в бакете) также поля, указывающие на предыдущий и следующий элементы относительно порядка вставки
- Устройство TreeMap [48] (**)
Краткий ответ
- Cбалансированное красно-черное дерево
- Реализует интерфейс NavigableMap [49], что позволяет возвращать из него элементы, больше (меньше) указанного, либо range элементов, находящийся в определенных границах
- Какой контракт Comparator [50] должен соблюдать?
Краткий ответ
Быть согласованным с equals()
- Есть ли способ сделать enum ключом Map? (**)
Краткий ответ
EnumMap [51] — массив, по размеру соотвествующий кол-ву элементов в enum'е. Индекс элемента массива соотвествуют ordinal'у из enum'а
- Расскажите про CopyOnWriteArrayList/CopyOnWriteHashSet [52] (**)
Краткий ответ
- СopyOnWriteArrayList [52] — иммутабельный list, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного списка
- СopyOnWriteHashSet [53] — иммутабельный set, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного set'а
- IdentityHashMap [54] — когда используется? (**)
Краткий ответ
IdentityHashMap [54] — используется, только если нужно проверять идентичность двух ссылок, а не эквивалентность двух объектов по ним. Например, если нужно отслеживать уже посешенные ноды в графе, или строить карту объекты-прокси. IdentityHashMap представляет из себя не классическую хэштаблицу со связанными списками, это linear probing map (бонус за объяснение работы linear probing)
- Интерфейсы Queue [55]/Deque [56] и их реализации (***)
Краткий ответ
- Queue [55] — коллекция, предоставляющая возможности упорядочения элементов в порядке вставки согласно принципу FIFO. Поддерживает два набора операций добавления/удаления/взятия элемента с конца — с возвращением спец. значения при исключительной ситуации (пустая или заполненная очередь), и с киданием exception'а
- Deque [56] — коллекция, предоставляющая возможность вставки значений в начала и в конец, позволяющая организовать очереди по принципам FIFO/LIFO. Предпочтительна для реализации стэка вместо Stack [57]. Ниже приведен набор операций для Deque:
- BlockingQueue [58] — очередь, блокирующая операции чтения take при пустой очереди или операции записи put при полной очереди. Есть наборы операций и с неблокирующей семантикой. Ниже определен полный список операций чтения/записи.
- ArrayBlockingQueue [59] — кольцевой bounded-buffer с внутренним capacity и fairness policy. Все операции чтения и записи защищены внутренним lock'ом (j.u.c.l.ReentrantLock), неявно связанным с двумя condition'ами — notFull, notEmpty. Соотвественно, если пишущий тред, захвативший общий lock, застрял на condition'е notFull, он неявно освобождает lock, чтобы читающий тред мог освободить очередь, и сигнализировать producer'у о том, что можно продолжать. Ровно и наоборот, читающий тред также захватывает общий lock, застревает на notEmpty, неявно освобождает lock, чтобы пишущий тред мог положить новый элемент и просигналить о непустой очереди. Т.е семантика такая же, как и у synchronized/wait/notify/notifyAll. Fairness = true позволяет предотвратить ситуации thread starvation для консьюмеров и продюсеров, но снизит производительность.
- LinkedBlockingQueue [60] — очередь, в которой элементы добавляются в связанный список, основанная на two-lock queue, описанного в статье Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott.
Секция IO:
- InputStream [61], OutputStream [62] и их buffered версии (*)
Краткий ответ
Далее, для краткости InputStream — is, OutputStream — os
is — побайтное чтение из сокета/файла/строки/другого байтового массива
os — побайтная запись в сокет/файл/другой байтовый массив
Buffered-версии нужны для оптимизации чтения/записей через отдельный буффер
- Зачем нужен Reader [63]? (*)
Краткий ответ
Reader позволяет указать
Charset [64] при чтении
- Serializable [65], serialVersionUID (*)
Краткий ответ
Классы, чьи объекты подвергаются сериализации/десериализации должны реализовывать marker интерфейс Serializable (и иметь статическое поле serialVersionUID для указании при сериализации, с какой версией класса данный объект был сериализован. Если serialVersionUID из сериализованного представления не совпадает c serialVersionUID класса «на том конце провода» — то кидается exception)
На практике, уже довольно редко используется, т.к тем же Jackson/GSON не обязательно наличие данного интерфейса для сериализации
- try-with-resources. AutoCloseable [66] (*)
Краткий ответ
try-with-resources — краткая замена стандартному try..catch..finally. Закрывает ресурс после выхода из секции try-with-resources. Ресурс должен имплементить интерфейс AutoCloseable.
«Ресурс» в данном контексте — это класс, представляющий cобой соединение/cокет/файл/поток
try (InputStream is = new FileInputStream("/path/to/file.txt")) {
...
}
Секция Exceptions:
- Отличие checked-exception/unchecked-exception. Error, Exception, RuntimeException (*)
Краткий ответ
- Checked exceptions (проверяемые исключения). В JDK представлены классом Exception. Исключения, которые нельзя проигнорировать, их обязательно нужно обрабатывать, либо специфицировать в сигнатуре метода, для обработки выше. Как правило, считаются дурным тоном, т.к код со мн-вом конструкций try..catch плохо читабелен, к тому же добавление новых пробрасываемых исключений в сигнатуре метода может сломать контракт вызова у пользователей данного метода.
- Unchecked exceptions (непроверяемые исключения). В JDK это класс RuntimeException. Можно игнорировать, не требуют обработки через try..catch, или указания в сигнатуре через throws. Минус такого подхода — у вызывающей стороны нет никакого понимания, как обрабатывать ситуацию, когда под капотом «рванет»
- Error — ошибки, кидаемые JVM в результате нехватки памяти (OutOfMemoryError), переполнения стэка (StackOverflowError) и.т.д
Полезные ссылки:
- Утечки памяти [7] — статья на TopTal.com
- Частичная реализация ConcHashMap [29] (аля Java 8) с нуля от kuptservol [30]
- Структура SkipList [32]
- Обзор коллекций [42] от JournalDev
- Обзор коллекций [67] от vedenin1980 [68]
- Обзор [69] пакета java.util.concurrency (Java 7) от Melnosta [70]
- Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (для сильных духом)
Автор: Олег
Источник [71]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/349010
Ссылки в тексте:
[1] Object: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html
[2] String: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html
[3] StringBuilder: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuilder.html
[4] StringBuffer: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuffer.html
[5] HashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html
[6] WeakHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/WeakHashMap.html
[7] статья: https://www.toptal.com/java/hunting-memory-leaks-in-java
[8] java.util.Random: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Random.html
[9] SecureRandom: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html
[10] Optional: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html
[11] Stream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html
[12] FunctionalInterface: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/FunctionalInterface.html
[13] FlowLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/FlowLayout.html
[14] GridLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/GridLayout.html
[15] BoxLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/swing/BoxLayout.html
[16] BorderLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/BorderLayout.html
[17] NoClassDefFoundError: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/NoClassDefFoundError.html
[18] NoSuchMethodError: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/NoSuchMethodError.html
[19] Condition: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/Condition.html
[20] Thread.UncaughExceptionHandler: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.UncaughtExceptionHandler.html
[21] ReentrantLock: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html
[22] Countdown Latch: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CountDownLatch.html
[23] Cyclic Barrier: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CyclicBarrier.html
[24] ThreadLocal: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ThreadLocal.html
[25] Double checked locking: https://ru.wikipedia.org/wiki/%D0%91%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BD%D0%BE%D0%B9_%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%BE%D0%B9
[26] ExecutorService: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ExecutorService.html
[27] Executors: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Executors.html
[28] ConcurrentHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html
[29] Частичная реализация ConcHashMap (аля Java 8) с нуля: https://habr.com/ru/post/327186/
[30] kuptservol: https://habr.com/ru/users/kuptservol/
[31] ConcurrentSkipListMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentSkipListMap.html
[32] здесь: https://habr.com/ru/post/139870/
[33] ThreadPoolExecutor: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ThreadPoolExecutor.html
[34] ScheduleThreadPoolExecutor: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ScheduledThreadPoolExecutor.html
[35] Iterable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Iterable.html
[36] Сollection: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html
[37] List: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
[38] ArrayList: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html
[39] Set: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html
[40] HashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html
[41] Map: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Map.html
[42] JournalDev: https://www.journaldev.com/1260/collections-in-java-tutorial
[43] LinkedList: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedList.html
[44] ListIterator: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ListIterator.html
[45] ConcurrentModificationException: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ConcurrentModificationException.html
[46] Hashtable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Hashtable.html
[47] LinkedHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html
[48] TreeMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/TreeMap.html
[49] NavigableMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/NavigableMap.html
[50] Comparator: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html
[51] EnumMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/EnumMap.html
[52] CopyOnWriteArrayList/CopyOnWriteHashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html
[53] СopyOnWriteHashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteHashSet.html
[54] IdentityHashMap: https://docs.oracle.com/javase/7/docs/api/java/util/IdentityHashMap.html
[55] Queue: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Queue.html
[56] Deque: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Deque.html
[57] Stack: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Stack.html
[58] BlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
[59] ArrayBlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ArrayBlockingQueue.html
[60] LinkedBlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/LinkedBlockingQueue.html
[61] InputStream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/InputStream.html
[62] OutputStream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/OutputStream.html
[63] Reader: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Reader.html
[64] Charset: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/charset/Charset.html
[65] Serializable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html
[66] AutoCloseable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/AutoCloseable.html
[67] Обзор коллекций: https://habr.com/ru/company/luxoft/blog/256877/
[68] vedenin1980: https://habr.com/ru/users/vedenin1980/
[69] Обзор: https://habr.com/ru/company/luxoft/blog/157273/
[70] Melnosta: https://habr.com/ru/users/melnosta/
[71] Источник: https://habr.com/ru/post/485678/?utm_source=habrahabr&utm_medium=rss&utm_campaign=485678
Нажмите здесь для печати.