Добрый день! Представляю вашему вниманию список вопросов к собеседованию Java Backend, которые я оформлял на протяжении около 2х лет.
Вопросы разбиты по темам: core, collections, concurrency, io, exceptions, которые задают основные направления хода технического собеседования. Звездочками отмечен субъективный (с точки зрения автора) уровень сложности вопроса, в сноске спойлера — краткий ответ на вопрос. Ответ представляет для интервьювера правильное направления развития мысли кандидата.
Опросник не претендует на роль исчерпывающего средства оценки технических навыков кандидата, это скорее еще одна компиляция вопросов и тем по Java и сопуствующим технологиям, принципам и концепциям разработки, коих в сети десятки. Она преследует цель собрать большое число технических вопросов, возникающих на собеседованиях, в удобном для читателей Хабра формате. Некоторые ответы следует воспринимать как мнемоники, «размечивающие» пространство поиска, так что глубже копать нужно уже в документации.
Также не стоит обращать внимание на слишком большое кол-во списков, так как это все-таки не вольное переложение авторских знаний с примесью литературной экспреcсии (что на хабре котируется и собирает аудиторию, особенно в пятницу). Этот список я составил для самого себя как способ структурировать основные тематики и типичные вопросы с собеседований, так что все дополнения и правки только приветствуются.
Это также не руководство к действию — не надо закидывать бедных кандидатов всеми вопросами из списка.
Секция Core:
- Назвать методы Object. (*)
Краткий ответ
- 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? (**)
Краткий ответ
- Строка в виде литерала сразу раскрывает пароль, плюс она всегда хранится в 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 — иммутабельный байтовый массив
- StringBuilder — helper-класс для построения строк, не предоставляет гарантий синхронизации
- StringBuffer — то же, что и 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 вместо WeakHashMap для кэширования чего-нибудь большого, например картинок ваших товаров, пользователей и.т.д в. Т.к ссылки на ключи сильные (strong references), значения по этим ключам будут висеть в хипе до
морковкиного заговеньяследующей перезагрузки jvm процесса или удаления ключа из мапы и обнуления ссылки на него. Вообще, кэширование — тема для отдельного разговора - Также, статья (но староватая)
- Как вернуть псевдо-случайную последовательность целых чисел/чисел с плавающей запятой? (**)
Краткий ответ
- В чем проблемы Random? (**)
Краткий ответRandom возвращает псевдо-случайную числовую последовательность, основанную на линейном конгруэнтном методе и seed'е, основанном на timestamp'е создания j.u.Random.
Соотвественно, зная время создания, можно предсказать такую последовательность. Такой генератор является детерминированным, и криптографически нестойким. Для исправления этого лучше использовать SecureRandom - GC и различные его виды в JVM. Какой объект считать достижимым. Как происходит сборка мусора (своими словами).(**)
Краткий ответВиды GC:
- Serial Stop the World
- Parallel
- CMS (В чем недостаток по сравнению с Parallel?)
- G1 (Назвать отличие от CMS)
- Shenandoah
Если объект является достижимым из стека или статической области, то он не поддается сборке мусора
- Java 8: стримы, функциональные интерфейсы, Optional (**)
Краткий ответStream — интерфейс, предоставляющий функциональные возможности обработки коллекций (filter, map, reduce, peek)
Операции на стримах делятся на терминальные и нетерминальные. Нетерминальные операции модифицируют pipeline операций над коллекцией, при этом не изменяя саму коллекцию, терминальные (например, collect) — проводят действия pipeline'а, возвращают результат и закрывают Stream.FunctionalInterface — аннотация, предоставляющая возможность использовать лямбды на месте интерфейсов (например, при передаче лямбды в качестве аргумента в метод)
Optional — интерфейс, предохраняющий пользовательский код от 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 может возникнуть, если нужной библиотеки с этим классом нет в classpath
- NoSuchMethodError может возникнуть из-за несовместимости ваших библиотек, если зависимая библиотека A вызывает метод из старой версии библиотеки B, но в classpath есть более новая версия библиотеки B, c другой сигнатурой этого метода
- Какими способами можно сконструировать объект в Java? (**)
Краткий ответ
- Через конструктор
- Через статический factory-method
- Через паттерн Builder
- Как идентифицируется класс в Java? (**)
Краткий ответПо его FQDN и classloader'у
- Bytecode: назовите какие-нибудь инструкции и опишите их (**).
Краткий ответЗдесь только краткий список команд:
- aload
- aconst
- astore
* Попросить описать принцип действия стековой машины, как бонус. Допустим, на примере вызова метода.
- 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
- 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 из другого треда? (***)
Краткий ответЗарегистрировать Thread.UncaughExceptionHandler
- ReentrantLock (**)
Краткий ответПримитив синхронизации, с помощью которого можно установить границы критической секции. Тред, перед входом в критическую секцию должен сделать захват c операцией
lock()
, после выхода из крит. секции — сделатьunlock()
. Другой тред в это время ожидает на lock'е (можно указывать таймаут ожидания), либо может проверить доступность черезtryLock()
.ReentrantLock обязательно нужно освобождать (такое кол-во раз, сколько раз он был захвачен), в противном случае будет thread starvation у других тредов, ожидающих у границы критической секции.
ReentrantLock может быть «честным» (fairness = true), тогда приоритет отдается тредам, ждущих на нем наибольшее кол-во времени, но это вроде как уменьшает производительностьlock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() }
- Countdown Latch/Cyclic Barrier (**)
Краткий ответCountdownLatch («защелка») — примитив синхронизации, с помощью которого, например, основной thread может ожидать выполнения работы остальных N тредов. Треды, выполняющие работу, выполняют countDown() на защелке, основной тред ожидает на операции await(). Когда счетчик достигает нуля, основной тред продолжает работу.
Для синхронизации N тредов (все ждут всех) и переиспользования используется CyclicBarrier, ему также можно указывать действие (через Runnable), выполняемое после синхронизации всех-со-всеми
- ThreadLocal (**)
Краткий ответКласс, предоставляющий доступ к операциям get/set в области видимости треда. Под капотом содержит кастомную реализацию мапы со слабыми ссылками на ключи-треды. Каждый тред имеет доступ только к своим данным.
- Создание singleton? (**)
Краткий ответ
- Наивным способом, с проверкой на null статического поля
- Double checked locking (объяснить проблемы double checked locking)
- Простой — инициализация статического поля, или через enum, т.к ленивая инициализация thread-safe по-умолчанию
- Способы запустить поток? (***)
Краткий ответ
- Переопределить Thread#run(), запустить через Thread#start()
- new Thread(Runnable).start()
- Через ExecutorService, используя utility-класс Executors
- ConcurrentHashMap (**)
Краткий ответConcurrentHashMap имеет разные реализации в 1.7 и 1.8 (что стало для меня неожиданностью).
Раньше параллелизм основывался на идее сегментирования хэштаблицы на основе заданного уровня параллелизма.
Начиная с Java 8 — это единый массив бакетов с lock-free (локинг на первой ноде бакета с cas-циклом) и конкурентным ресайзингом.
Частичная реализация ConcHashMap (аля Java 8) с нуля от kuptservol - ConcurrentSkipListMap
Краткий ответLock-free структура данных, хранящая упорядоченный набор элементов, с O(log N) временем доступа/удаления/вставки и weakly-consistent итераторами. Под капотом содержит структуру SkipList, предоставляющую собой слои связных списков, от верхнего к нижнему, элементы верхнего списка ссылаются на элементы нижнего списка под ними. Вероятность попадания элемента при вставке в самый нижний список — 1.0, далее она равняется p (либо 1/2, либо 1/4 как правило) — вероятности попадания элемента из нижнего списка в верхний. Таким образом, на самом верхнем будет вставлено минимальное кол-во элементов. Skiplist — вероятностная структура данных. Подробнее и доходчиво про skiplist описано здесь. Полезна, если стоит задача отсортировать поток событий, одновременно читаемый несколькими тредами, которым нужно делать срез по временному интервалу. Более медленные операции по сравнению с ConcurrentHashMap
- Thread states (**)
Краткий ответ
- NEW
- RUNNABLE
- BLOCKED(monitor lock)
- WAITING(Thread.join)
- TERMINATED
- Deadlocks, условия наступления, как избежать: (***)
Краткий ответ
- Условия наступления — эксклюзивность доступа к ресурсам, наличие циклов в графе ожиданий ресурсов, отсуствие таймаутов на ожидание
- Как избежать — задать порядок доступа к ресурсам. Всегда обращение в порядке либо Thread1->Thread2, либо Thread2->Thread1
- ThreadPoolExecutor — описать механизм работы, св-ва, частности (fixed threadpool, scheduled, single thread executor) (***)
Краткий ответThreadPoolExecutor — средство контроля исполнения параллельных задач, задействует один из свободных тредов в общем пуле, или ставит задание в очередь, если таковых нет, или достигнуты определенные условия (ниже)
Основными св-вами ThreadPoolExecutor являются corePoolSize и maxPoolSize. Если текущее количество тредов в пуле < corePoolSize — новый тред будет создаваться в независимости от того, есть ли в пуле незанятые треды. В промежутке между corePoolSize и maxPoolSize тред будет создаваться в том случае, если заполнена очередь задач, и удаляться спустя keepAliveTime. Если кол-во тредов стало >= maxPoolSize — новые треды не создаются, а задачи ставятся в очередь.
Есть возможность регулировать поведение очереди:
- Direct handoffs: немедленная передача задачи тредпулу. Нет понятия очереди задачи. Если свободных тредов нет — кидается exception. Применимо при неограниченных maxPoolSize, но нужно понимать проблему при быстрых записях и медленных чтениях, что может спровоцировать непомерное потребление ресурсов
- Unbounded queues: очередь без ограничений. Задачи будут добавляться в нее при превышении corePoolSize, при этом maxPoolSize будет игнорироваться. Unbounded queues имеют проблемы потребления ресурсов при больших нагрузках, но сглаживают рост тредов при пиках.
- Bounded queues: очередь с ограничениями. Задачи будут добавляться в очередь до достижения некоего capacity. Для достижения наилучшей производительности нужно понимать размеры corePoolSize и самой очереди и чем можно пожертвовать — перфомансом (малый corePoolSize и большая очередь), или же памятью (ограниченная очередь, большой corePoolSize)
Частности ThreadPoolExecutor:
- ScheduleThreadPoolExecutor — применяется для периодичных по времени задач
- fixed thread pool — частность ScheduleThreadPoolExecutor'а с настроенным corePoolSize и unbounded queue
- single thread executor — тредпулл, c сorePoolSize = 1, гарантирующий последовательное выполнение задач из очереди
Секция Collections:
- Рассказать про java.util.collection. (*)
Краткий ответ
- Iterable — реализуют коллекции, по которым можно проитерироваться
- Сollection — общий интерфейс для коллекций
- List (стандартная реализация ArrayList) — список с массивом элементов, с возможностью случайного доступа элемента по индексу за O(1), вставкой/удалением со сложностью O(n)
- Set (стандартная реализация HashSet) — мн-во элементов без дубликатов. Нет возможности доступа по индексу, есть вставка и удаление за O(1)
- Map (стандартная реализация HashMap) — мн-во пар элементов «ключ-значение». Доступ по ключу/добавление/удаление за O(1) при оптимальном случае, O(n) — при вырожденном
Обзор по коллекциям от JournalDev
- Устройство ArrayList, LinkedList, HashMap, HashSet. Когда следует использовать. Контракт equals/hashcode для Map, Set (*)
Краткий ответОбзор по коллекциям от JournalDev
- Итератор по коллекции, его св-ва и интерфейс (*)
Краткий ответ
- Может только один раз проходить по коллекции. Для прохождения в двух направлениях есть ListIterator
- Если в foreach цикле структурно модифицировать коллекцию, при последующем обращению к элементу (неявно через итератор) получим ConcurrentModificationException (fail-fast)
- hasNext(), next() — основные методы
- Hashtable vs HashMap (*)
- Java 8,11: новые методы в Map (**)
Краткий ответ
- Java 8: compute
- Java 8: computeIfAbsent
- Java 8: computeIfPresent
- Java 8: forEach
- Java 8: putIfAbsent
- Java 11: factory-методы of()
- LinkedHashMap, зачем он нужен (**)
Краткий ответ
- Позволяет сохранять порядок вставки пар key-value в Map
- Каждый entry содержит помимо hash, value, next (следующий элемент в бакете) также поля, указывающие на предыдущий и следующий элементы относительно порядка вставки
- Устройство TreeMap (**)
Краткий ответ
- Cбалансированное красно-черное дерево
- Реализует интерфейс NavigableMap, что позволяет возвращать из него элементы, больше (меньше) указанного, либо range элементов, находящийся в определенных границах
- Какой контракт Comparator должен соблюдать?
Краткий ответБыть согласованным с equals()
- Есть ли способ сделать enum ключом Map? (**)
Краткий ответEnumMap — массив, по размеру соотвествующий кол-ву элементов в enum'е. Индекс элемента массива соотвествуют ordinal'у из enum'а
- Расскажите про CopyOnWriteArrayList/CopyOnWriteHashSet (**)
Краткий ответ
- СopyOnWriteArrayList — иммутабельный list, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного списка
- СopyOnWriteHashSet — иммутабельный set, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного set'а
- IdentityHashMap — когда используется? (**)
Краткий ответIdentityHashMap — используется, только если нужно проверять идентичность двух ссылок, а не эквивалентность двух объектов по ним. Например, если нужно отслеживать уже посешенные ноды в графе, или строить карту объекты-прокси. IdentityHashMap представляет из себя не классическую хэштаблицу со связанными списками, это linear probing map (бонус за объяснение работы linear probing)
- Интерфейсы Queue/Deque и их реализации (***)
Краткий ответ
- Queue — коллекция, предоставляющая возможности упорядочения элементов в порядке вставки согласно принципу FIFO. Поддерживает два набора операций добавления/удаления/взятия элемента с конца — с возвращением спец. значения при исключительной ситуации (пустая или заполненная очередь), и с киданием exception'а
- Deque — коллекция, предоставляющая возможность вставки значений в начала и в конец, позволяющая организовать очереди по принципам FIFO/LIFO. Предпочтительна для реализации стэка вместо Stack. Ниже приведен набор операций для Deque:
- BlockingQueue — очередь, блокирующая операции чтения take при пустой очереди или операции записи put при полной очереди. Есть наборы операций и с неблокирующей семантикой. Ниже определен полный список операций чтения/записи.
- ArrayBlockingQueue — кольцевой 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 — очередь, в которой элементы добавляются в связанный список, основанная на two-lock queue, описанного в статье Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott.
Секция IO:
- InputStream, OutputStream и их buffered версии (*)
Краткий ответДалее, для краткости InputStream — is, OutputStream — os
is — побайтное чтение из сокета/файла/строки/другого байтового массива
os — побайтная запись в сокет/файл/другой байтовый массив
Buffered-версии нужны для оптимизации чтения/записей через отдельный буффер - Зачем нужен Reader? (*)
Краткий ответReader позволяет указать Charset при чтении
- Serializable, serialVersionUID (*)
Краткий ответКлассы, чьи объекты подвергаются сериализации/десериализации должны реализовывать marker интерфейс Serializable (и иметь статическое поле serialVersionUID для указании при сериализации, с какой версией класса данный объект был сериализован. Если serialVersionUID из сериализованного представления не совпадает c serialVersionUID класса «на том конце провода» — то кидается exception)
На практике, уже довольно редко используется, т.к тем же Jackson/GSON не обязательно наличие данного интерфейса для сериализации
- try-with-resources. AutoCloseable (*)
Краткий ответ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) и.т.д
Полезные ссылки:
- Утечки памяти — статья на TopTal.com
- Частичная реализация ConcHashMap (аля Java 8) с нуля от kuptservol
- Структура SkipList
- Обзор коллекций от JournalDev
- Обзор коллекций от vedenin1980
- Обзор пакета java.util.concurrency (Java 7) от Melnosta
- Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (для сильных духом)
Автор: Олег