...

понедельник, 9 марта 2020 г.

Вопросы к собеседованию Java-backend, Java core (60 вопросов)

image

Добрый день! Представляю вашему вниманию список вопросов к собеседованию 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 (**)
    Краткий ответ
    1. Создать класс Point2D c полями x,y: double
    2. Унаследовать от него класс ColoredPoint2D c доп. полем color
    3. a: Point2D
    4. b: ColoredPoint2D
    5. 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'ов
    1. Bootstrap
    2. System
    3. 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:
      1. Читаем старое значение
      2. Перед set'ом проверяем старое значение, если оно не изменилось, сетаем старое + 1
      3. Если изменилось, в след. итерации получаем «новое» старое, далее см. п. 1

  • Редкий вопрос — как поймать exception из другого треда? (***)
  • 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 (*)
    Краткий ответ
    • Hashtable — legacy, thread safe, методы синхронизированы, поэтому работа с Hashtable (обращение, удаление, добавление) в целом накладнее
    • HashMap — не 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, зачем он нужен (**)
    Краткий ответ
    • Позволяет сохранять порядок вставки пар 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) и.т.д

Полезные ссылки:

  1. Утечки памяти — статья на TopTal.com
  2. Частичная реализация ConcHashMap (аля Java 8) с нуля от kuptservol
  3. Структура SkipList
  4. Обзор коллекций от JournalDev
  5. Обзор коллекций от vedenin1980
  6. Обзор пакета java.util.concurrency (Java 7) от Melnosta
  7. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (для сильных духом)

Let's block ads! (Why?)

Комментариев нет:

Отправить комментарий