1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/yangdechao_admin-guage-notes

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
20大厂面试总结.md 170 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 24.06.2025 02:12 0782333

1. Основы работы с хеш-таблицами

Хеш-таблица (или хеш-таблица, также называемая таблицей рассеивания) — это структура данных, которая позволяет непосредственно обращаться к записям по ключевому значению (ключевому коду). Это достигается путём отображения ключевых значений на позицию в таблице, что ускоряет поиск. Эта функция отображения называется хеш-функцией, а сама таблица, где хранятся записи, называется хеш-таблицей.

Дана таблица M, существует функция f(key), так что для любого заданного ключевого значения key, после применения функции получается адрес записи в таблице, содержащей это ключевое значение. В этом случае говорят, что таблица M является хеш-таблицей, а функция f(key) — хеш-функцией.

2. Методы решения конфликтов хеш-алгоритмами

1) Открытый адресМетод открытого адреса заключается в том, что при возникновении конфликта ищется следующий свободный хеш-адрес. Если таблица достаточно большая, то всегда можно найти свободный хеш-адрес и поместить запись в него. При использовании метода открытого адреса, когда происходит конфликт, применяется определённая техника поиска, которая создаёт последовательность поиска. По этой последовательности последовательно проверяются ячейки, пока не будет найдено заданное ключевое значение или не будет найдено свободное место (если требуется вставка, то новая запись помещается в свободное место). Если поиск завершается на свободной ячейке, то это указывает на отсутствие ключевого значения в таблице, то есть поиск неудачен.### 2) Двойная хеш-функция

Метод двойной хеш-функции, также известный как метод вторичного хеширования, использует несколько различных хеш-функций. При возникновении конфликта используется вторая, третья и так далее хеш-функции для вычисления адреса, пока не будет найдено свободное место. Хотя этот метод снижает вероятность образования агрегации, он увеличивает время вычислений.

3) Метод цепочек

Основная идея метода цепочек состоит в том, что каждый узел хеш-таблицы имеет указатель next, который позволяет нескольким узлам образовать односвязный список. Узлы, которые были распределены в одну и ту же позицию, могут быть соединены этим односвязным списком. Например, если пары ключ-значение k2, v2 и k1, v1 после применения хеш-функции имеют одинаковое значение индекса 2, то возникает конфликт, но они могут быть соединены через указатели next, что решает проблему конфликта хеш-таблицы.

4) Создание общего зонного участка

Этот метод использует разделение хеш-таблицы на основную таблицу и зональный участок. Все элементы, которые вызывают конфликты с основной таблицей, помещаются в зональный участок.

3. Различия между Minor GC, Major GC и Full GC### 1) Minor GC (молодое поколение)

Минорная ГЧ (Minor GC) происходит в молодой области (молодое поколение), которая включает зону Eden и зону Survivor. Когда молодое поколение не может выделить память для новых объектов, это вызывает Минорную ГЧ. Большинство объектов в молодом поколении имеют короткий срок жизни, поэтому частота Минорной ГЧ очень высока. Хотя она приводит к остановке всего мира (stop-the-world), её скорость сборки мусора достаточно высока.

2) Основной сборщик мусора (Major GC)Основной сборщик мусора очищает старшее поколение (Tenured Generation), используемое для сборки мусора в старшем поколении. При возникновении основного сборчика мусора обычно происходит как минимум одна сборка мусора в младшем поколении.

3) Полная сборка мусора (Full GC)

Полная сборка мусора направлена на весь молодой поколение, старшее поколение и пространство метаданных (metaspace, заменяет perm gen начиная с версии Java 8). Полная сборка мусора не равна основному сборщику мусора, также она не равна сумме младшего и основного сборщиков мусора. Происхождение полной сборки мусора зависит от используемого сочетания сборщиков мусора, что позволяет объяснить тип сборки мусора.

4. Расскажите о сборщике мусора CMS в JVM (не полное описание)

CMS = конкурентный + маркировка-очистка + старшее поколение

CMS — это конкурентный сборщик мусора, использующий алгоритм маркировки-очистки (Mark-Sweep), который предназначен для сборки мусора в старшем поколении.

5. Структура данных zset в Redis и принцип ее работы

Упорядоченные множества могут быть закодированы как ziplist или skiplist. При выполнении следующих условий используется кодировка ziplist:

  • Количество элементов меньше 128
  • Длина всех значений member меньше 64 байт

Максимальные значения этих условий могут быть изменены через параметры zset-max-ziplist-entries и zset-max-ziplist-value.Упорядоченные множества, закодированные с использованием ziplist, хранятся в компактных списках, где первый элемент представляет собой значение member, а второй — score. Элементы в ziplist сортируются по возрастанию score.

Для упорядоченных множеств, закодированных с использованием skiplist, используется структура данных, состоящая из словаря и прыжкового списка. Прыжковый список сортируется по возрастанию score, а словарь содержит отображение значений member на score, что позволяет находить score для каждого member за O(1).

Описание прыжкового списка Прыжковый список (skip list) — это случайная структура данных, основанная на параллельных связях. Вставка, удаление и поиск имеют сложность O(log N). Можно сказать, что прыжковый список является видом списка, но с дополнительной возможностью прыгать, что обеспечивает сложность поиска элементов O(log N). Структура может выглядеть следующим образом:

## 6. Сравнение прыжкового списка с балансированными деревьями и хеш-таблицами

Элементы в структурах данных типа skip-list и различных сбалансированных деревьев (например, AVL, красно-черное дерево и т. д.) располагаются в порядке возрастания, тогда как элементы хеш-таблицы не упорядочены. Поэтому в хеш-таблице можно выполнять поиск только по одному ключу, а поиск по диапазону значений неэффективен. Под поиском по диапазону значений понимается поиск всех узлов, значения которых находятся между двумя заданными значениями.

  • При выполнении поиска по диапазону значений операции со сбалансированными деревьями сложнее, чем с skip-list. В сбалансированном дереве после нахождения минимального значения диапазона требуется продолжить поиск остальных узлов, не превышающих максимальное значение диапазона, используя порядок следования узлов (in-order traversal). Без определенной модификации сбалансированного дерева выполнение этого порядка следования может быть затруднительно. В то же время поиск по диапазону значений в skip-list значительно проще: достаточно найти минимальное значение диапазона и последовательно пройтись по первому уровню списка.- Вставка и удаление элементов в сбалансированном дереве могут вызвать перестройку поддеревьев, что усложняет логику работы, тогда как вставка и удаление в skip-list требуют лишь изменения указателей соседних узлов, что делает эти операции простыми и быстрыми.
  • С точки зрения использования памяти, skip-list более гибкий вариант по сравнению со сбалансированным деревом. Обычно каждый узел сбалансированного дерева содержит два указателя (на левое и правое поддерево), тогда как среднее количество указателей в каждом узле skip-list составляет 1/(1-p), что зависит от параметра p. Например, если взять p=1/4, как это сделано в реализации Redis, то среднее количество указателей в каждом узле составит 1.33, что является преимуществом перед сбалансированным деревом.
  • Временная сложность поиска одного ключа в skip-list и сбалансированном дереве одинакова и составляет O(log n), тогда как временная сложность поиска в хеш-таблице при условии низкого уровня коллизий близка к O(1), что делает её более эффективной. Именно поэтому большинство используемых нами структур данных типа Map или dictionary основаны на хеш-таблицах. ## Что такое hashMap?### 1) Структура hashMap

В JDK7 используется массив + связанный список;

В JDK8 используется массив + связанный список + красно-черное дерево.

При увеличении размера в JDK7 возможно возникновение мертвых узлов,而在JDK8中通过算法优化消除了这一问题。

В JDK8 также упрощена хеш-функция для повышения производительности вычислений.

2) Разрешает ли hashMap пустые ключи и значения?

HashMap допускает только один пустой ключ (несколько приведёт к замене), но допускает несколько пустых значений.

3) Важные параметры, влияющие на производительность hashMap

Исходная емкость: количество корзин (элементов массива) при создании HashMap, по умолчанию 16 Загрузочный фактор: степень заполненности хеш-таблицы перед автоматическим увеличением её размера, по умолчанию 0.75

4) Как работает hashMap

HashMap основана на принципе хеширования. Мы используем put(key, value) для хранения объекта в HashMap, а get(key) для его получения из HashMap.

5) Почему длина массива в hashMap всегда является степенью двойки?

  • Степени двойки удобны для битовых операций и обеспечивают высокую производительность.
  • Это позволяет распределить добавляемые элементы равномерно по всему массиву hashMap, что снижает коллизии хешей.

Когда HashMap вычисляет положение добавляемого элемента, она использует битовые операции, что делает это особенно эффективным.Кроме того, начальная емкость HashMap является степенью двойки, и увеличение происходит в два раза. Это позволяет равномерно распределять добавляемые элементы по массиву HashMap, что снижает коллизии хешей и предотвращает образование длинных списков, что снижает скорость запросов!

6) Почему по умолчанию используется 16?

Официального объяснения от JDK нет, поэтому это скорее опыт. Если необходимо установить значение по умолчанию как 2^n, то нужно найти компромисс между производительностью и использованием памяти. Это значение не должно быть слишком маленьким или большим.

Если оно слишком маленькое, то увеличение размера будет происходить слишком часто, что снижает производительность. Если оно слишком большое, то это приведет к нерациональному использованию памяти.

Поэтому значение 16 было выбрано как опытное значение.

7) Почему в Java 8 используется красно-черное дерево?Например, если кто-то найдет ваши значения коллизий хешей, он может заставить вашу HashMap постоянно сталкиваться с коллизиями, что приведет к росту длинного списка с одинаковым ключом. Когда вам нужно получить доступ к этому месту в HashMap, вы будете циклически проходить через этот огромный список, что существенно снижает производительность. Java 8 использует красно-черное дерево вместо длинного списка более чем из 8 элементов, что значительно улучшает производительность запросов, с O(n) до O(log n).

8) Когда hashMap использует связный список для преобразования в красно-черное дерево?Количество элементов в связном списке больше 8 и длина массива больше или равно 64, тогда связный список преобразуется в красно-черное дерево

Только когда количество элементов в связном списке больше 8 (тогда узел имеет 9 элементов), и длина массива больше или равно 64, связный список будет преобразован в красно-черное дерево.

9) Когда hashMap использует связный список для обратного преобразования в связный список?

Когда количество элементов в связном списке равно 6, он будет обратно преобразован в связный список. В промежуточной стадии есть разница 7, чтобы предотвратить частое переключение между связным списком и деревом. Предположим, если бы было предусмотрено, что при превышении количества элементов в связном списке 8 он преобразуется в структуру дерева, а при меньшем количестве элементов в связном списке 8 структура дерева преобразуется обратно в связный список, то при постоянном вставлении и удалении элементов в HashMap, количество элементов в связном списке будет колебаться около 8, что приведет к частому преобразованию связного списка в дерево и обратно, что значительно снижает производительность.

10) Почему hashMap выбирает красно-черное дерево?

Красно-черное дерево обеспечивает стабильное время выполнения операций вставки, удаления и поиска, которое не превышает O(log n). Это делает его подходящим выбором для реализации HashMap, поскольку оно гарантирует эффективное управление количеством элементов и предотвращает проблемы, связанные с линейным поиском в длинных связных списках.- Поскольку AVL-деревья имеют худшую производительность при вставке или удалении узлов по сравнению с красно-черным деревом. В AVL-деревьях высота левого и правого поддерева не может отличаться более чем на 1. Поэтому поддержание этой структуры требует значительных затрат по производительности. Основная причина заключается в том, что для изменения и поддержания высоты AVL-дерева требуется выполнение операций поворота, тогда как для красно-черного дерева достаточно изменения цвета узлов.- Двоичное дерево поиска имеет несбалансированное левое и правое поддерево, и при этом корень фиксируется сразу, поэтому в крайнем случае это может стать связным списком.

  • Чем длиннее связный список, тем ниже скорость вставки и поиска.

  • Красно-черное дерево обеспечивает высокую скорость поиска, вставки и удаления узлов.

8. Подробное описание ArrayList

1. Что такое ArrayList? Для чего он используется?

ArrayList представляет собой упорядоченный динамический массив, который主要用于装载数据,只能装载包装类(Integer,String,Double等),其主要底层实现是数组Object[] elementData

2. Какие различия между ArrayList и LinkedList?

  • Обращение к элементам и поиск элементов в ArrayList происходит быстрее, но добавление и удаление элементов происходит медленнее. В LinkedList обращение к элементам и поиск элементов происходит медленнее, но добавление и удаление элементов происходит быстрее.
  • ArrayList требует непрерывного участка памяти, LinkedList не требует непрерывного участка памяти (особенно при создании ArrayList, размер непрерывного участка памяти должен быть больше или равен размеру создаваемого массива).
  • Оба они являются неатомарными (не потокобезопасными).

3. Почему используют его, если он не является потокобезопасным?

Перевод:

8. Подробное описание ArrayList

1. Что такое ArrayList? Для чего он используется?

ArrayList представляет собой упорядоченный динамический массив, который主要用于装载数据,只能装载包装类(Integer,String,Double等),其主要底层实现是数组Object[] elementData

2. Какие различия между ArrayList и LinkedList?

  • Обращение к элементам и поиск элементов в ArrayList происходит быстрее, но добавление и удаление элементов происходит медленнее. В LinkedList обращение к элементам и поиск элементов происходит медленнее, но добавление и удаление элементов происходит быстрее.
  • ArrayList требует непрерывного участка памяти, LinkedList не требует непрерывного участка памяти (особенно при создании ArrayList, размер непрерывного участка памяти должен быть больше или равен размеру создаваемого массива).
  • Оба они являются неатомарными (не потокобезопасными).

3. Почему его используют, если он не является потокобезопасным?


Продолжение перевода:

1. Что такое ArrayList? Для чего он используется?

ArrayList представляет собой упорядоченный динамический массив, который主要用于装载数据,只能装载包装类(Integer,String,Double等),其主要底层实现是数组Object[] elementData

2. Какие различия между ArrayList и LinkedList?

  • Обращение к элементам и поиск элементов в ArrayList происходит быстрее, но добавление и удаление элементов происходит медленнее. В LinkedList обращение к элементам и поиск элементов происходит медленнее, но добавление и удаление элементов происходит быстрее.
  • ArrayList требует непрерывного участка памяти, LinkedList не требует непрерывного участка памяти (особенно при создании ArrayList, размер непрерывного участка памяти должен быть больше или равен размеру создаваемого массива).
  • Оба они являются неатомарными (не потокобезопасными).

3. Почему его используют, если он не является потокобезопасным?

Его используют потому что он предоставляет эффективное решение для хранения и управления коллекцией объектов в памяти. Кроме того, ArrayList предоставляет простой и эффективный способ работы с коллекциями, особенно когда требуется быстрый доступ к элементам. Однако, если требуется потокобезопасность, следует использовать другие коллекции, такие как Vector или CopyOnWriteArrayList.Потому что в обычных сценариях использования данные используются для чтения, и не требуется слишком частое добавление или удаление данных. Если требуется частое добавление или удаление данных, можно использовать LinkedList.### 4. Внутренняя реализация основана на массиве, но размер массива является фиксированным. Если мы будем постоянно добавлять данные, не возникнет ли проблем?- JDK 1.7 — эквивалент паттерна Singleton (голодный): при первом создании объекта через конструктор без параметров создается массив с начальной емкостью 10.

  • JDK 1.8 — эквивалент паттерна Singleton (ленивый): при создании объекта через конструктор без параметров создается пустой массив. Начальная емкость массива равна нулю, и только при первом добавлении данных массив расширяется до значения DEFAULT_CAPACITY = 10.

5. Когда происходит увеличение емкости ArrayList?

Первое увеличение емкости происходит при первом вызове метода add(), когда емкость составляет 10. При достижении количества элементов 11 (то есть превышении текущей емкости) происходит увеличение емкости до 1.5 раз от текущей емкости (округление вниз).

6. Различия между версиями JDK 1.7 и 1.8 при инициализации

В JDK 1.7 при инициализации создается массив с начальной емкостью 10, а в JDK 1.8 при инициализации создается пустой массив, который увеличивается до емкости 10 при первом вызове метода add().

7. Является ли ArrayList потокобезопасным?

Нет, для обеспечения потокобезопасности можно использовать Vector, Collections.synchronizedList() или CopyOnWriteArrayList. Эти коллекции обеспечивают потокобезопасность путем применения synchronized к методам.

8. Подходит ли ArrayList для использования как очередь?

Нет, для использования как очередь лучше всего подходит LinkedList.Очереди обычно реализуются как FIFO (первым пришел — первым ушел). Если использовать ArrayList как очередь, потребуется добавлять данные в конец массива и удалять их из начала. Однако любое из этих действий требует перемещения данных внутри массива, что может быть затратным с точки зрения производительности. Заключение: ArrayList не подходит для использования как очередь.### 9. Подходит ли массив для использования как очередь?

Массив вполне подходит для этой цели. Например, внутренняя реализация ArrayBlockingQueue представляет собой круговую очередь, которая использует фиксированный массив. Также известна библиотека Disruptor, которая использует круговой массив для создания высокопроизводительной очереди. Принцип работы заключается в использовании двух смещений для отслеживания местоположения чтения и записи в массиве. Если смещение превышает длину массива, оно возвращается к началу массива, при условии, что массив имеет фиксированную длину.

9. Что такое 2MSL

Что такое MSLMSL — это аббревиатура от Maximum Segment Lifetime, что можно перевести как "максимальный срок жизни сегмента". Это время, в течение которого любой сегмент данных может существовать в сети передачи данных; если этот срок истекает, сегмент будет отброшен. Поскольку TCP-сегмент является частью IP-пакета, а IP-головка содержит поле TTL (Time To Live), которое определяется исходной машиной, но не представляет собой конкретное время, а указывает на максимальное количество маршрутов, через которые может пройти IP-пакет. Каждый раз, когда пакет проходит через маршрутизатор, значение TTL уменьшается на единицу, и если значение TTL достигнет нуля, пакет будет отброшен, а маршрутизатор отправит ICMP-сообщение обратно к исходной машине. В RFC 793 указано, что MSL составляет 2 минуты, хотя в реальных приложениях часто используется значение 30 секунд, 1 минута или 2 минуты.### Что такое 2MSL

2MSL — это двойное значение MSL. Состояние TIME_WAIT протокола TCP также известно как состояние ожидания 2MSL. Когда одна сторона TCP-соединения активно завершает соединение, она отправляет последний ACK-пакет после третьего рукопожатия. После этого соединение переходит в состояние TIME_WAIT и должно находиться в этом состоянии в течение времени, равного двум MSL. Основная цель этого состояния заключается в том, чтобы гарантировать, что последний ACK-пакет был получен другой стороной; если ACK-пакет не был получен, другая сторона может повторно отправить FIN-пакет, и активно завершающая сторона сможет ответить ACK-пакетом. В состоянии TIME_WAIT оба конца не могут использовать свои порты до окончания времени 2MSL. Время 2MSL также гарантирует, что любые поздние пакеты будут отброшены. Однако в реальных приложениях можно использовать опцию SO_REUSEADDR для использования порта без необходимости ждать окончания времени 2MSL.

10. Какие различия между HashMap, LinkedHashMap и TreeMap?

HashMap

HashMap реализует интерфейс Map, где ключи не имеют определенного порядка. Таким образом, HashMap неупорядочен и не допускает дублирования ключей.

LinkedHashMap

LinkedHashMap также реализует интерфейс Map, но в отличие от HashMap, он сохраняет порядок вставки ключей. Это позволяет просматривать элементы в том порядке, в котором они были добавлены.LinkedHashMap наследуется от HashMap и дополнительно поддерживает двусвязный список, который позволяет итерировать элементы в порядке их вставки, начиная с головы или хвоста списка. Это делает LinkedHashMap упорядоченным. Однако из-за дополнительного двусвязного списка, он требует больше памяти и имеет немного меньшую производительность по сравнению с HashMap. Тем не менее, если важна последовательность вставки элементов, то LinkedHashMap может быть хорошим выбором. LinkedHashMap обеспечивает порядок вставки и доступа.### TreeMap

TreeMap реализует интерфейс Map и использует бинарное дерево для хранения элементов, что обеспечивает автоматическую сортировку ключей. Различие между TreeMap и HashMap: в отличие от HashMap, TreeMap использует красно-черное дерево в качестве своего внутреннего представления. Временная сложность методов containsKey, get, put и remove составляет log(n). Элементы в TreeMap сортируются по ключам в порядке их естественной сортировки (или по указанной сортировке). По умолчанию ключи сортируются по возрастанию, но можно изменить порядок сортировки, создав класс, реализующий интерфейс Comparator и переопределив метод compare.

11. Какие различия между HashMap в JDK 1.8 и JDK 1.7?1. В JDK 1.8 объект entry был заменён на Node, хотя Node всё ещё наследует Entry.

  1. В JDK 1.8 при длине списка связанных узлов больше или равной 8 список преобразуется в красно-черное дерево.
  2. В JDK 1.8 при добавлении элемента в список связанных узлов происходит полное прохождение всего списка, после чего новый элемент добавляется в конец списка (метод "добавление в конец"). В JDK 1.7 при добавлении элемента в список связанных узлов используется метод "добавление в начало", при котором весь список сдвигается вниз.
  3. В JDK 1.8 сначала добавляется элемент, а затем проверяется необходимость увеличения размера контейнера. В JDK 1.7 сначала проверяется необходимость увеличения размера контейнера, а затем добавляется новый элемент.
  4. В JDK 1.7 при многопоточной работе и перемещении данных могут возникнуть циклические ссылки, что приведёт к появлению бесконечных циклов. В JDK 1.8 благодаря использованию высокого и низкого битовых значений такие проблемы не возникают.## 12. Три типа ввода-вывода в Java (BIO, NIO, AIO)

1) BIO (синхронное блокирующее вводо-выводное устройство)

BIO - это синхронное блокирующее вводо-выводное устройство, которое обрабатывает данные в виде потока (низкая производительность).

Программирование сокетов является примером BIO, где один сокет-соединение обслуживается одним потоком. Когда несколько сокетов пытаются установить соединение с сервером, сервер не может предоставить достаточное количество потоков для каждого соединения, поэтому некоторые соединения могут быть заблокированы или отклонены.

2) NIO (синхронное неблокирующее вводо-выводное устройство)

NIO - это улучшение над BIO, оно представляет собой синхронное неблокирующее вводо-выводное устройство, которое обрабатывает данные в виде блока (высокая производительность). NIO использует каналы и буферы для выполнения операций с данными. Данные всегда читаются из канала в буфер или записываются из буфера в канал. Selector (выборка) используется для прослушивания множества каналов (например, запросы на подключение, прибытие данных и т.д.), поэтому можно использовать один поток для прослушивания множества клиентских каналов.

Три основных компонента NIO: каналы (channels), буферы (buffers), выборщики (selectors)

3) AIO (асинхронное неблокирующее вводо-выводное устройство)Сначала операционная система завершает запрос клиента, а затем уведомляет сервер о необходимости запуска потока для обработки запроса.

Сравнение типов ввода-вывода| Сравнительная таблица | BIO | NIO | AIO | | --------------------- | -------- | ---------- | ---------- | | Тип IO | Синхронный блокирующий | Синхронный неблокирующий | Асинхронный неблокирующий | | Сложность использования API | Простая | Сложная | Сложная | | Надежность | Низкая | Высокая | Высокая | | Производительность | Низкая | Высокая | Высокая |BIO Подходит для соединений с низкой частотой, но большим потреблением серверных ресурсов, при этом программирование является простым. Это синхронный блокирующий режим.

Пример: Вы приходите в ресторан и заказываете еду, затем вы должны ждать там, ничего не делая, пока еда не будет готова.

NIO Используется для архитектур с большим количеством соединений и короткими временами соединения, таких как чат-серверы, где программирование более сложное. Это синхронный, но не блокирующий режим.

Пример: Вы приходите в ресторан, заказываете еду, затем можете уйти играть. Через некоторое время вы возвращаетесь в ресторан и спрашиваете, готова ли еда.AIO Подходит для архитектур с большим количеством соединений и длительными временами соединения, таких как серверы альбомов, где используется параллельное выполнение операций с участием ОС, и программирование более сложное. Это асинхронный, но не блокирующий режим.## 13. Концепция хэш-слотов в Redis

В Redis-кластере встроено 16384 хэш-слота. Когда требуется поместить ключ-значение в Redis-кластер, Redis сначала использует алгоритм CRC16 для ключа, чтобы получить результат, затем этот результат делится на 16384, чтобы получить остаток. Таким образом, каждый ключ соответствует хэш-слоту с номером от OnClickListener 0 до 16383. Redis распределяет эти хэш-слоты между различными узлами примерно равномерно в зависимости от количества узлов.

14. Как ZooKeeper обеспечивает последовательную согласованность транзакций?

ZooKeeper использует глобально увеличивающийся идентификатор транзакции (zxid), который используется для идентификации всех предложений (proposals). Все предложения добавляются в zxid при их предложении. ZXID — это 64-битное число, где верхние 32 бита представляют эпоху (период; эра; век; новую эру), которая используется для идентификации периода лидерства. Если появляется новый лидер, эпоха увеличивается. Нижние 32 бита используются для увеличения счетчика. При создании нового предложения, оно проходит через двухэтапный процесс базы данных. Сначала отправляется запрос на выполнение транзакции другим серверам. Если более половины машин могут успешно выполнить транзакцию, то она начинает выполняться.## 15. Режимы работы и запуска Tomcat

1) Режимы работы

Как контейнер servlet, Tomcat имеет три режима работы:

    1. Независимый контейнер servlet, где контейнер servlet является частью веб-сервера;
    1. Внутренний контейнер servlet, где контейнер servlet реализуется как плагин веб-сервера и контейнер Java, плагин веб-сервера открывает JVM внутри внутреннего адресного пространства, позволяя контейнеру Java работать внутри. Ответ быстро, но недостаточно гибок;
    1. Внешний контейнер servlet, где контейнер servlet работает вне адресного пространства веб-сервера и реализуется как сочетание плагина веб-сервера и контейнера Java. Ответ медленнее, чем внутренний, но более гибок и стабилен. Входящие в Tomcat запросы могут быть разделены на следующие две категории в зависимости от режима работы Tomcat:
  • Tomcat как сервер приложений: запросы поступают от переднего веб-сервера, такого как Apache, IIS, Nginx и т.д.;

  • Tomcat как независимый сервер: запросы поступают от веб-браузера;

2) Режимы выполнения

Часто встречающиеся типы соединителей в файле server.xml обычно включают четыре:

  1. HTTP-соединитель
  2. SSL-соединитель
  3. AJP 1.3-соединитель
  4. Прокси-соединитель

Соединители Tomcat имеют три режима выполнения:- bio (blocking I/O) Это блокирующее I/O-операция, что означает, что Tomcat использует традиционные Java I/O операции (т.е. пакет java.io и его подпакеты). Один поток обрабатывает один запрос, недостаток: при высокой нагрузке количество потоков увеличивается, что приводит к расточительному использованию ресурсов.

  • nio (new I/O) Java NIO представляет собой Java API, основанный на буферах и предоставляющий асинхронные I/O-операции. Поэтому NIO также может рассматриваться как non-blocking I/O. Он имеет лучшую производительность при параллельной работе по сравнению с традиционными I/O-операциями (bio). Используя асинхронные запросы I/O Java, можно обрабатывать большое количество запросов с помощью небольшого количества потоков.

  • apr (Apache Portable Runtime / Apache Portable Runtime) Tomcat использует JNI для вызова ядра динамической библиотеки сервера Apache HTTP для обработки операций чтения файлов или сетевой передачи, что значительно повышает производительность Tomcat при обработке статических файлов. Режим APR является предпочтительным для запуска приложений с высокой нагрузкой на Tomcat.## 16. Различия между MyISAM и InnoDB

  • InnoDB поддерживает транзакции, MyISAM нет. Для InnoDB каждая SQL-команда автоматически оборачивается в транзакцию и автоматически выполняется, что может замедлить скорость выполнения. Поэтому лучше объединять несколько SQL-команд между begin и commit, чтобы создать одну транзакцию;

  • InnoDB поддерживает внешние ключи, MyISAM нет. Преобразование таблицы InnoDB с внешними ключами в MyISAM завершится ошибкой;

  • InnoDB использует упорядоченные индексы, использует B+Tree как структуру индекса, файлы данных связаны с первичным ключом индексом (файл данных сам по себе является B+Tree организованной структурой индекса). Обязательно наличие первичного ключа, поиск по первичному ключу очень эффективен. Однако вторичные индексы требуют двух запросов: сначала найти первичный ключ, затем использовать его для поиска данных. Поэтому первичный ключ не должен быть слишком большим, так как большие первичные ключи приводят к большим вторичным индексам. MyISAM использует неупорядоченные индексы, также использует B+Tree как структуру индекса, индексы и файлы данных разделены. Индекс хранит указатели на файлы данных. Первичные и вторичные индексы являются независимыми.

  • InnoDB не сохраняет конкретное количество строк в таблице, поэтому выполнение запроса SELECT COUNT(*) FROM table требует полного сканирования всей таблицы. В то время как MyISAM использует переменную для хранения общего количества строк в таблице, что позволяет выполнять указанный запрос просто считывая значение этой переменной, что происходит очень быстро (не забудьте, что WHERE условие не должно присутствовать).- InnoDB не поддерживает полнотекстовый индекс, тогда как MyISAM поддерживает полнотекстовый индекс, что делает его быстрее при выполнении запросов, связанных с полнотекстовым поиском; PS: с версии 5.7 InnoDB также поддерживает полнотекстовый индекс.

  • Таблицы MyISAM могут быть сжаты и затем использованы для выполнения запросов.

  • InnoDB поддерживает блокировку таблиц, строк (по умолчанию), тогда как MyISAM поддерживает только блокировку таблиц.

  • InnoDB требует наличия уникального индекса (например, первичного ключа) (если пользователь не указал, система сама найдет или создаст скрытый столбец Row_id для использования в качестве первичного ключа), тогда как MyISAM может обойтись без него. Файлы хранения InnoDB включают frm и ibd, а MyISAM — frm, MYD и MYI. Для InnoDB: frm — это файл определения таблицы, ibd — файл данных. Для MyISAM: frm — это файл определения таблицы, myd — файл данных, myi — файл индексов.

17. Установленные по умолчанию сборщики мусора в JDK 7, 8, 9- JDK 1.7 по умолчанию использует сборщик мусора Parallel Scavenge (молодое поколение [маркировка-копирование]) + Parallel Old (старшее поколение [маркировка-упаковка]).

  • JDK 1.8 по умолчанию использует сборщик мусора Parallel Scavenge (молодое поколение) + Parallel Old (старшее поколение).
  • JDK 1.9 по умолчанию использует сборщик мусора G1 [локально (между двумя Region) реализовано с помощью "маркировка-копирование", глобально (в целом) реализовано с помощью "маркировка-упаковка"].

Перевод заключенного в кавычки текста:

  • "маркировка-копирование" → "маркировка-копирование"
  • "маркировка-упаковка" → "маркировка-упаковка"## 18. Какие ресурсы являются общими между потоками, а какие — уникальными?

1) Общие ресурсы

a. Куча Поскольку куча выделяется в пространстве процесса, она является естественно общей; следовательно, все, что создается с помощью new, является общим (на платформах с 16-битной адресацией есть глобальная куча и локальная куча, где локальная куча является уникальной).

b. Глобальные переменные Они не связаны с конкретной функцией, поэтому они также не связаны с конкретным потоком; следовательно, они являются общими.

c. Статические переменные Хотя для локальных переменных они "расположены" внутри какой-то функции, но их место хранения совпадает с глобальными переменными, они находятся в .bss и .data сегментах, выделенных из кучи, и являются общими.

d. Файлы и другие общие ресурсы Это общие ресурсы, используемые этими общими ресурсами потоки должны быть синхронизированы. Win32 предоставляет несколько способов синхронизации ресурсов, включая сигналы, критические секции, события и мьютексы.

2) Уникальные ресурсы

a. Стек Стек является уникальным.

b. Регистры Это может вызвать путаницу, поскольку компьютерные регистры физически существуют, каждый поток получает копию значений, включая программный счетчик PC.

19. Четыре необходимых условия для возникновения мертвых locks

Чтобы произошло возникновение мертвых locks, должны выполняться четыре условия:

  1. Несоответствие порядка блокировки Разные потоки блокируют ресурсы в различных порядках.
  2. Постоянное владение блокировками Потоки не освобождают блокировки до тех пор, пока не завершат выполнение.
  3. Отсутствие времени ожидания Потоки не используют время ожидания при попытке получить блокировку.
  4. Отсутствие возможности прерывания Потоки не могут быть прерваны или перезапущены при попытке получить блокировку.### 1) Условие взаимоисключения

Каждый ресурс может использоваться одновременно только одним процессом;

2) Условие запроса и удержания

Процесс, который был заблокирован из-за запроса ресурса, продолжает удерживать уже захваченные ресурсы;

3) Условие недопустимости отбора

Ресурсы, которые были захвачены процессом, не могут быть отобраны до тех пор, пока они не будут полностью использованы;

4) Условие циклического ожидания

Несколько процессов образуют циклическую последовательность ожидания ресурсов друг у друга;

20. Различия между кучей и стеком в Java

1) Куча

  • Куча Java — это область данных, доступная во время выполнения программы, где создаются объекты. Эти объекты создаются с помощью инструкций, таких как new, и уничтожаются методом сборки мусора.
  • Преимущество кучи заключается в возможности динамического выделения памяти, то есть количество требуемой памяти не должно быть известно компилятору заранее, так как оно выделяется динамически во время выполнения. Однако недостаток заключается в том, что поскольку память выделяется динамически во время выполнения, скорость доступа к ней ниже.
  • В куче хранятся объекты и массивы, созданные с помощью new, куча работает по принципу первым пришёл — первым ушёл.

2) Стек- В стеке хранятся переменные основных типов данных (byte, short, int, long, float, double, boolean, char) и ссылки на объекты.

  • Преимущество стека заключается в более высокой скорости доступа к данным по сравнению с кучей, а также в возможности совместного использования данных в стеке. Однако недостаток заключается в том, что размер памяти, занимаемой данными в стеке, должен быть определён во время компиляции, что ограничивает гибкость.
  • В стеке хранятся методы или локальные переменные, стек работает по принципу последним пришёл — первым ушёл.## 21. Обычные команды для просмотра информации о ресурсах в Linux

1) Система

# uname -a               # Просмотр версий ядра/операционной системы/CPU
# lsb_release -a         # Просмотр версии операционной системы (работает для всех версий Linux, включая RedHat, SUSE, Debian и другие, но в Debian необходимо установить lsb)
# cat /proc/cpuinfo      # Просмотр информации о CPU
# hostname               # Просмотр имени компьютера
# lspci -tv              # Просмотр всех устройств PCI
# lsusb -tv              # Просмотр всех устройств USB
# lsmod                  # Просмотр загруженных модулей ядра
# env                    # Просмотр переменных окружения

2) Ресурсы

# free -m                # Просмотр использования памяти и swap
# df -h                  # Просмотр использования разделов диска
# du -sh <directory name># Просмотр размера указанного каталога
# grep MemTotal /proc/meminfo   # Просмотр общего объёма памяти
# grep MemFree /proc/meminfo    # Просмотр свободного объёма памяти
# uptime                 # Просмотр времени работы системы, количиства пользователей и нагрузки
# cat /proc/loadavg      # Просмотр средней нагрузки системы

3) Диск и разделы

# mount | column -t      # Просмотр состояния подключенных разделов
# fdisk -l               # Просмотр всех разделов
# swapon -s              # Просмотр всех разделов swap
# hdparm -i /dev/hda     # Просмотр параметров диска (только для устройств IDE)
# dmesg | grep IDE       # Просмотр состояния обнаружения устройств IDE при запуске системы
```### 4) Сеть

ifconfig # Просмотреть свойства всех сетевых интерфейсов

iptables -L # Просмотреть настройки брандмауэра

route -n # Просмотреть таблицу маршрутизации

netstat -lntp # Просмотреть все прослушиваемые порты

netstat -antp # Просмотреть все установленные соединения

netstat -s # Просмотреть статистику сети


### 5) Процессы

ps -ef # Просмотреть все процессы

top # В реальном времени отслеживать состояние процессов


### 6) Пользователи

w # Просмотреть активных пользователей

id <имя пользователя> # Просмотреть информацию о конкретном пользователе

last # Просмотреть журнал входа пользователей

cut -d: -f1 /etc/passwd # Просмотреть всех пользователей системы

cut -d: -f1 /etc/group # Просмотреть все группы системы

crontab -l # Просмотреть расписание задач для текущего пользователя


### 7) Услуги

chkconfig --list # Просмотреть все службы системы

chkconfig --list | grep on # Просмотреть все запущенные службы системы


### 8) Программы

rpm -qa # Просмотреть все установленные пакеты


## 22. Просмотр занятых портов в Linux

1. Проверить, занят ли какой-то порт, эту команду нужно выполнять с правами root или через sudo, иначе вывод будет пустым

sudo lsof -i:порт

2. Проверить, занят ли какой-то порт

netstat -anp|grep порт


```shell
ps -ef
# Часто используется вместе с grep для поиска процессов
ps -ef | grep имя_процесса
# Отображение процессов в виде дерева
pstree

24. Различия между режимом ядра и режимом пользователя

Операционная система требует двух уровней работы процессора: Режим ядра (Kernel Mode): выполнение программ ОС, работа с оборудованием Режим пользователя (User Mode): выполнение пользовательских программ

  • Режим ядра и режим пользователя — это два уровня работы операционной системы. Когда программа работает на уровне привилегий 3, она считается работающей в режиме пользователя. Это самый низкий уровень привилегий, который обычно используют обычные пользовательские процессы;

  • Когда программа работает на уровне привилегий 0, она считается работающей в режиме ядра. Программы, выполняемые в пользовательском режиме, не могут непосредственно обращаться к данным структур ядра операционной системы и программам. Когда мы запускаем программу в системе, большую часть времени она работает в пользовательском режиме, а при необходимости помощи операционной системы для выполнения задач, которые она не имеет права или возможности выполнить самостоятельно (например, управление аппаратными средствами), происходит переход в режим ядра.- Основное различие между этими двумя режимами заключается в следующем:

    • В пользовательском режиме доступ к памяти и объектам ограничен, а процессор, который используется процессом, может быть отнят другим процессом.
    • В режиме ядра доступен весь объём памяти и все объекты, а процессор, используемый процессом, не может быть отнят другим процессом.

25. Хэш-индексы в MySQL

Хэш-индексы имеют специфическую структуру, что обеспечивает высокую скорость поиска. Поиск по хэш-индексу позволяет сразу находить нужную запись, в отличие от B+ деревьев, где поиск требует последовательного прохождения от корневого узла до листовых узлов с множеством операций чтения/записи. Почему же все не используют хэш-индексы, а предпочитают B+ деревья?

  1. Хэш-индексы поддерживают только запросы типа "=","IN","<=>", но не поддерживают запросы с диапазоном значений. Это связано с тем, что порядок хэш-значений после применения алгоритма хэширования не обязательно совпадает с порядком исходных значений.

  2. Хэш-индексы не могут использоваться для избежания сортировки данных. Поскольку порядок хэш-значений не обязательно совпадает с порядком исходных ключей.3. Хэш-индексы не могут использоваться для частичного поиска по ключам. Для составных индексов хэш-значение вычисляется для всей комбинации ключей, а не для каждого ключа отдельно, поэтому частичный поиск по составному индексу невозможен.4. Хэш-индексы никогда не могут полностью избежать сканирования таблицы. Из-за того, что различные ключи могут иметь одинаковое хэш-значение, даже если известно количество записей, удовлетворяющих определенному хэш-ключу, требуется обращение к данным таблицы для получения информации.

  3. При наличии большого количества ключей с одинаковым хэш-значением производительность хэш-индекса не обязательно будет выше, чем у B+ дерева.

26. Объекты GC Root

Виртуальная машина Java (JVM) + статические свойства области методов + константы области методов + стек вызова JNI

(1) Объекты, на которые ссылаются в стеке виртуальной машины Java (JVM) (2) Объекты, на которые ссылаются статические свойства в области методов (3) Объекты, на которые ссылаются константы в области методов (константы final) (4) Объекты, на которые ссылаются в стеке вызова JNI

27. Пятиуровневая модель сети

Пятиуровневая модель сети состоит из следующих уровней:1. Физический уровень: Отвечает за передачу битов через физические каналы связи. 2. Уровень связи: Отвечает за установление и поддержание соединения между устройствами. 3. Уровень интернета: Отвечает за маршрутизацию пакетов данных между сетями. 4. Транспортный уровень: Отвечает за надежную доставку данных между источником и приемником. 5. Уровень приложений: Отвечает за представление данных в удобном для пользователя виде. Пятиуровневая архитектура включает в себя: прикладной уровень, транспортный уровень, сетевой уровень, уровень данных и физический уровень.Три модели структуры:

Каждый уровень соответствует сетевым протоколам:

28. Что такое HTTPS?

HTTPS — это HTTP с добавлением слоя шифрования SSL для шифрования передаваемых данных. Это безопасная версия протокола HTTP. Основные функции HTTPS:

  1. Шифрование данных и создание безопасного канала для защиты информации во время передачи;
  2. Аутентификация реального имени сервера.

29. В чем отличие HTTPS от HTTP?

  1. HTTPS — это зашифрованный протокол передачи, а HTTP — нет;
  2. Для использования HTTPS требуется сертификат SSL, а HTTP не требует;
  3. HTTPS более безопасен, чем HTTP, и лучше воспринимается поисковыми системами, что положительно влияет на SEO [см. (1) Google предпочитает индексировать HTTPS-страницы для защиты конфиденциальности пользователей, (2) Baidu открывает доступ к HTTPS-сайтам, переход на HTTPS становится неотвратимым];
  4. Стандартный порт для HTTPS — OnClickListener 443, для HTTP — 80;
  5. HTTPS основан на транспортном уровне, а HTTP — на прикладном уровне;
  6. В браузере HTTPS отображается зелёным значком безопасности, а HTTP — нет.В целом, HTTPS более безопасен, чем HTTP, и эффективно защищает конфиденциальность пользователей. Именно поэтому число сайтов, использующих HTTPS, постоянно растёт. Если вы не хотите, чтобы ваш сайт попал в новости из-за утечки данных, вам следует получить сертификат SSL и обеспечить шифрование вашего сайта с помощью HTTPS!## 30. Какие типы индексов используются в MySQL?

1. Из точки зрения структуры данных

1) Индекс B+дерева (O(log(n)))

Для получения информации о B+ деревьях можно обратиться к статье "MySQL: принципы работы индексов и алгоритмы".

2) Хэш-индекс

а) Поддерживает запросы типа "=", "IN" и "<=>", но не поддерживает запросы диапазона; б) Высокая скорость поиска, так как хэш-индекс позволяет найти данные за один шаг, в отличие от B-дерева, где требуется несколько операций чтения; в) Поддерживается только движком Memory.

3) Полный текстовый индекс (FULLTEXT)

(теперь поддерживается движками MyISAM и InnoDB).

4) Индекс R-дерева (красно-черное дерево)

(используется для создания пространственного индекса для типов данных GIS).

2. Из точки зрения физического хранения

1) Упорядоченный (или кластерный) индекс (clustered index)

2) Некластерный индекс (non-clustered index)

3. Логическая сторона1) Первичный ключ индекс: первичный ключ индекс — это специальный уникальный индекс, который не допускает пустых значений.

  1. Обычный индекс или одиночный индекс.
  2. Индекс с несколькими столбцами (составной индекс): составной индекс — это индекс, созданный на нескольких полях. Он будет использоваться только в том случае, если в условии запроса используется первый столбец, используемый при создании индекса. При использовании составного индекса следует следовать правилу левого префикса.
  3. Уникальный индекс или непростой индекс.
  4. Пространственный индекс: пространственный индекс — это индекс, созданный на поле пространственного типа данных. В MySQL есть четыре пространственных типа данных: GEOMETRY, POINT, LINESTRING и POLYGON.## 31. Различие между CyclicBarrier, CountDownLatch и Semaphore

1) CountDownLatch

  • Когда какой-либо поток вызывает метод await, этот поток блокируется.
  • Поток, вызывающий метод countDown, не блокируется.
  • Когда значение CountDownLatch становится равным нулю, все потоки, вызывающие метод await, освобождаются и продолжают выполнение.

Основные методы: когда один или несколько потоков вызывают метод await(), они блокируются, а другие потоки, вызывающие метод countDown(), уменьшают значение счетчика на единицу (потоки, вызывающие метод countDown(), не блокируются). Когда значение счетчика становится равно нулю, все потоки, вызывающие метод await(), освобождаются и продолжают выполнение.

Пример

public class CountDownLatchDemo {
    // Когда шесть учеников покинут класс, класс будет заперт
    public static void main(String[] args) throws InterruptedException {

        // Создаем объект CountDownLatch и задаем начальное значение
        CountDownLatch countDownLatch = new CountDownLatch(6);

        // Шесть учеников по очереди покидают класс
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " ученик учится");
                System.out.println(Thread.currentThread().getName() + " ученик играет");
                System.out.println(Thread.currentThread().getName() + " ученик покидает класс");
                // Уменьшаем счетчик на 1
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }

2) CyclicBarrier

  • Когда какой-либо поток вызывает метод await, этот поток блокируется до тех пор, пока не достигнет определенного количества потоков.
  • Когда все потоки достигнут состояния await, они освобождаются и продолжают выполнение.

3) Semaphore

  • Когда какой-либо поток вызывает метод acquire, этот поток блокируется до тех пор, пока не станет доступной семафорная лицензия.
  • Когда поток вызывает метод release, он освобождает одну семафорную лицензию.

Продолжение документа следует за этим разделом. new Thread(() -> { // Ждем try { // Поток классного руководителя ждет, пока счетчик CountDownLatch не станет равным нулю countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " классный руководитель запирает дверь и уходит"); }, Thread.currentThread().getName()).start(); } } ### 2) CyclicBarrierCyclicBarrier также называют циклическим барьером. Использование типа CyclicBarrier противоположно использованию CountDownLatch:

Ожидание завершения всех потоков перед выполнением следующего метода; например, если на встречу приходят семь человек, то встреча может начаться только тогда, когда все семь человек соберутся, в противном случае придется ждать.

Основные методы:

public int await() throws InterruptedException, BrokenBarrierException;
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException;
  • Вызов потока await() указывает, что поток достиг барьера.
  • BrokenBarrierException указывает на то, что барьер был поврежден, причина повреждения может заключаться в том, что один из потоков был прерван или истекло время ожидания во время вызова await().

Пример кода:

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo2 {

    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new Thread(() -> {
            System.out.println("Все участники собрались, начальник компании начинает собрание");
        }));
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " пришел в конференц-зал");
                    cyclicBarrier.await(); // указывает, что текущий поток находится вне циклического барьера и ожидает
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, Thread.currentThread().getName()).start();
        }
    }
}
```### 3) Семафор

Семафор обычно называют семафором. Он используется для контроля количества одновременно доступных потоков к определенному ресурсу, координируя работу потоков для рационального использования ресурса.

Можно представить его как информационный экран на въезде на парковку. Каждый раз, когда автомобиль заезжает на парковку, счетчик свободных мест уменьшается на единицу, а когда автомобиль выезжает с парковки, счетчик увеличивается на единицу. Когда количество свободных мест становится нулевым, шлагбаум на въезде не открывается, и автомобили больше не могут заехать на парковку, пока какой-то автомобиль не выедет с парковки.

**Сценарии использования**

Обычно используются в ситуациях, где есть ограничение на количество одновременно доступных ресурсов, например, для ограничения скорости.

Например, пусть это будет пул соединений с базой данных, где количество одновременно активных соединений ограничено. Когда количество активных соединений достигнет лимита, новые потоки будут вынуждены ждать освобождения соединений.

Например, сценарий парковки, где количество мест ограничено. Когда все места заняты, новые автомобили не смогут заехать на парковку, пока какой-то автомобиль не выедет с парковки.

**Описание часто используемых методов Semaphore**```java
acquire()  
Получает разрешение, поток остается заблокированным до тех пор, пока не получит разрешение или не будет прерван другим потоком.

acquire(int permits)  
Пытается получить указанное количество разрешений, поток остается заблокированным до тех пор, пока не получит разрешения или не будет прерван другим потоком или не истечет время ожидания.

acquireUninterruptibly() 
Получает разрешение, игнорируя прерывание, поток остается заблокированным до тех пор, пока не получит разрешение.

tryAcquire()
Пытается получить разрешение, возвращает true, если разрешение было успешно получено, иначе false, не блокирует поток.

tryAcquire(long timeout, TimeUnit unit)
Пытается получить разрешение, повторяет попытки получения разрешения до истечения времени ожидания, возвращает true, если разрешение было успешно получено, иначе false, не блокирует поток.

release()
Освобождает разрешение, пробуждает заблокированный поток, который не смог получить разрешение.

hasQueuedThreads()
Проверяет наличие заблокированных потоков в очереди.

getQueueLength()
Возвращает количество заблокированных потоков в очереди.

drainPermits()
Сбрасывает все разрешения, возвращает количество сброшенных разрешений.

availablePermits()
Возвращает количество доступных разрешений.

Использование Semaphore для реализации знака на парковкеКаждый вход на парковку имеет знак, который показывает количество свободных мест. Когда свободных мест нет, новые автомобили не могут заехать на парковку, пока какой-то автомобиль не покинет парковку; тогда знак обновляет количество свободных мест.

32. Какие различия между HashSet и TreeSet?

1) HashSet

Не гарантирует порядок элементов, порядок может меняться. Может содержать null, но только один null. HashSet использует HashMap для реализации. HashSet использует хеш-таблицу для реализации.

2) TreeSet

Элементы TreeSet отсортированы, не может содержать null. TreeSet реализован через TreeMap, где используется только ключ. TreeSet использует красно-черное дерево для реализации.

33. Принцип и внутренняя реализация LinkedHashMap

При использовании HashMap иногда требуется выполнить проход по таблице хешей в порядке добавления элементов. Однако, как мы знаем из предыдущего описания HashMap, в нем нет механизма для сохранения порядка.

В LinkedHashMap можно сохранять два типа порядка: порядок добавления и порядок доступа. Этот тип порядка можно указать при инициализации LinkedHashMap. По сравнению с порядком доступа, порядок вставки используется чаще, поэтому по умолчанию используется порядок вставки.

Пример

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapTest {
    public static void main(String[] args) {
        Map<String, String> test = new LinkedHashMap<String, String>();
```        test.put("Химия", "93");
        test.put("Математика", "98");
        test.put("Биология", "92");
        test.put("Английский", "97");
        test.put("Физика", "94");
        test.put("История", "96");
        test.put("Китайский", "99");
        test.put("География", "95");

        for (Map.Entry entry : test.entrySet()) {
            System.out.println(entry.getKey().toString() + ":" + entry.getValue().toString());
        }
    }
}

Реализация

  1. В LinkedHashMap используется двусвязный список для поддержания порядка вставки узлов. Программа выше в памяти выглядит следующим образом, каждый узел связан двусвязно, поддерживая порядок вставки (по умолчанию). head указывает на первый вставленный узел, а tail указывает на последний узел.
  2. LinkedHashMap является прямым потомком HashMap, наследуя класс HashMap. Узлы в LinkedHashMap имеют тип Entry<K,V>, который наследует HashMap.Node<K,V>.

34. Для чего используются интерфейсы Comparable и Comparator? Какие между ними различия?

Java предоставляет интерфейс Comparable, содержащий только один метод compareTo(). Этот метод позволяет сравнивать два объекта и упорядочивать их. Конкретнее, он возвращает отрицательное число, 0 или положительное число, чтобы показать, что входной объект меньше, равен или больше существующего объекта.Java также предоставляет интерфейс Comparator, который содержит два метода: compare() и equals(). Метод compare() используется для сравнения двух входных параметров и возвращает отрицательное число, 0 или положительное число, чтобы показать, что первый параметр меньше, равен или больше второго параметра. Метод equals() принимает объект в качестве параметра и используется для определения, равен ли входной параметр текущему Comparator. Этот метод возвращает true, только если входной параметр также является Comparator и его результаты сравнения совпадают с результатами текущего Comparator.Интерфейс Comparable используется для сортировки, если класс реализует интерфейс Comparable, это означает, что "этот класс поддерживает сортировку". Интерфейс Comparator является компаратором, который можно использовать для управления порядком сортировки определенного класса. Мы можем легко заметить: Comparable эквивалентен "внутреннему сопоставлению", а Comparator эквивалентен "внешнему сопоставлению".

35. Подробное описание интерфейса Comparable в Java

В Java интерфейс Comparable является одним из часто используемых. Например, при сортировке коллекций или массивов мы часто используем Arrays.sort() или Collections.sort(). Когда объекты в коллекции являются пользовательскими, у нас есть два способа применения методов сортировки к коллекции (массиву) пользовательских объектов.

36. Различие между Collection и Collections

1) Collection

java.util.Collection является родительским интерфейсом для всей коллекционной системы Java. Он предоставляет общие методы для выполнения базовых операций над коллекциями. Интерфейс Collection имеет множество конкретных реализаций в Java-библиотеке. Основное значение интерфейса Collection заключается в обеспечении максимальной унифицированности подходов к работе с различными конкретными коллекциями.

Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└SetВключённые методы:

2) Collections

java.util.Collections представляет собой упаковочный класс. Он содержит различные статические полиморфные методы для работы с коллекциями. Этот класс не может быть инстанцирован и используется как утилитный класс для обслуживания Java-коллекционного фреймворка.

37. Какой структурой данных пользуется MySQL для индексов? Почему используют B+ дерево?

MySQL использует B+ дерево для индексов.

Почему именно B+ дерево? Есть несколько причин:

  • Если бы использовалось AVL-балансированное двоичное дерево, высота дерева была бы слишком большой, что привело бы к большому количеству запросов к диску. Поскольку каждый запрос к диску выполняется по узлу, необходимо минимизировать количество операций чтения/записи. Поэтому высота дерева не должна быть слишком большой. В реальных условиях высота B+ дерева составляет около 4 или 5 для хранения миллионов записей.
  • B+ деревья часто сравниваются с B-деревьями. Одним из главных преимуществ B+ дерева является то, что все ключи находятся в цепочке листьев (плотный индекс), и ключи в этой цепочке упорядочены. Для поиска диапазона значений, например от 15 до 50, B-дерево требует выполнения ин-ордерного прохода по дереву, тогда как B+ дерево позволяет последовательно просматривать листовые узлы.## 38. Что такое принцип левого префикса?

Принцип левого префикса: при создании составного индекса в MySQL следует придерживаться принципа левого префикса, то есть при поиске данных поиск начинается с левого конца составного индекса. Пример: у нас есть таблица student, в которой мы создали составной индекс index_major_class(major, class), состоящий из двух полей.

Основа индекса — это B+ дерево, поэтому составной индекс также основан на B+ дереве, но узлы этого дерева содержат несколько значений, разделённых запятыми.

Пример: создание составного индекса index_major_class(major, class) выглядит следующим образом:

Он сначала сортируется по major, затем по class. Если индекс содержит ещё больше полей, то сортировка продолжается по этим полям.

Если условие WHERE содержит только класс, то составной индекс не будет использоваться. Однако если условие содержит только major, то составной индекс может быть использован (почему "может", потому что план выполнения MySQL и фактическое выполнение запроса могут не совпадать, например, при небольшом объёме данных базы данных полное сканирование может быть быстрее, чем использование индекса).

39. Использовали ли вы MyBatis? Чем вы знакомы с первичным и вторичным кэшированием?

1) Первичный кэшПервичный кэш MyBatis представляет собой SQLSession. Область действия первого кэша — это SQLSession. MyBatis по умолчанию активирует первый кэш. В рамках одного и того же SQLSession, при выполнении одинаковых SQL-запросов; первый запрос выполняется в базе данных и записывается в кэш, второй запрос берёт данные из кэша. Если между двумя запросами происходит операция внесения, удаления или изменения данных, кэш SQLSession очищается. Каждый запрос сначала проверяет наличие данных в кэше, если данные отсутствуют, они извлекаются из базы данных и записываются в кэш. Внутренний кэш MyBatis использует HashMap, где ключом является хеш-код + statementId + SQL-запрос, а значением — коллекция объектов Java, полученных из запроса. После выполнения операций insert, update, delete и commit SQLSession кэш очищается.

Принцип:

Первичный кэш использует HashMap для хранения данных. При выполнении запроса MyBatis сначала проверяет наличие данных в кэше, если данных нет, они извлекаются из базы данных. Если SQLSession выполняет clearCache(), commit или любую другую операцию внесения, удаления или изменения данных, кэш очищается.Как долго живется первичный кэш?1. При открытии базового сеанса данных MyBatis создает новый объект SqlSession, в котором содержится новый объект Executor, а внутри последнего — новый объект PerpetualCache; при завершении сеанса объект SqlSession, а также содержащиеся в нем объекты Executor и PerpetualCache освобождаются. 2. Если метод close() вызывается объектом SqlSession, освобождается первичный кэш PerpetualCache, который становится недоступным; 3. Если метод clearCache() вызывается объектом SqlSession, данные в объекте PerpetualCache очищаются, но сам объект остается доступным для использования; 4. При выполнении любого оператора update (update(), delete(), insert()) в объекте SqlSession данные в объекте PerpetualCache очищаются, но сам объект остается доступным для использования.### 2) Вторичный кэшПервичный кэш используется в рамках одной sqlSession, а вторичный кэш — в рамках одного namespace, поэтому sqlSession с одинаковым namespace могут использовать второй кэш.

Почему его называют "вторичным кэшем"? Это относится к "первичному кэшу". Если есть первый кэш, зачем нужен второй кэш? Мы знаем, что в первичном кэше, при выполнении одинаковых SQL-запросов различными сессиями, база данных проверяется дважды. Очевидно, это является ненужной тратой времени. Если SQL-запросы одинаковы, нет необходимости повторно обращаться к базе данных, достаточно использовать данные из кэша. Эта идея лежит в основе вторичного кэша MyBatis.

Кроме того, при интеграции Spring и MyBatis после каждого запроса закрывается sqlSession, и данные очищаются. Поэтому после интеграции MyBatis и Spring первый кэш становится бесполезным. Если включить второй кэш, закрытие sqlSession приведет к перемещению данных из первого кэша sqlSession во второй кэш namespace маппера. Таким образом, данные остаются в кэше даже после закрытия sqlSession.

<cache eviction="FIFO" flushInterval="60000" size="51024" readOnly="true"/>

Доступные стратегии очистки:- LRU – Least Recently Used: удаляет объекты, которые реже всего использовались.

  • FIFO – First In First Out: удаляет объекты в порядке их добавления в кэш.

  • SOFT – Soft Reference: удаляет объекты на основе состояния сборщика мусора и правил мягких ссылок.

  • WEAK – Weak Reference: активнее удаляет объекты на основе состояния сборщика мусора и правил слабых ссылок.## 40. Как настроить репликацию MySQL?

  • При изменении данных на мастере они сразу записываются в бинарный лог.

  • Слэйв запускает I/O поток для подключения к мастеру и запроса изменений бинарного лога.

  • Полученные I/O потоком изменения бинарного лога сохраняются в реляционный лог слэйва.

  • Слэйв имеет SQL поток для периодической проверки реляционного лога на наличие изменений. При наличии изменений данные обновляются.

41. Объектные заголовки и состав объекта в JVM

Дополнение 1: Создание пустого Java объекта в JVM требует минимум 3 байта для заголовка объекта, 1 байт для ссылки и 2 байта для заголовка объекта. Дополнение 2: Создание пустого Java массива в JVM требует минимум 4 байта для заголовка объекта, 1 байт для ссылки и 3 байта для заголовка объекта.

В JVM существует два способа хранения заголовков объектов (на примере 32-битной JVM):

1.1. Обычный объект

|--------------------------------------------------------------|
|                      Заголовок Объекта (64 бита)              |
|------------------------------------|-------------------------|
|           Маркер Слова (32 бита)   |     Класс Слово (32 бита)|
|------------------------------------|-------------------------|

1.2. Array Objects

|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32 bits)      |    Class Word(32 bits)|  array length(32 bits) |
|--------------------------------|-----------------------|------------------------|
```**Структура объектного заголовка**

Заголовок Java-объекта состоит из следующих трёх частей:

Mark Word (32 бита)
Указатель на класс (32 бита)
Длина массива (32 бита, применимо только к объектам массива)

**Mark Word**

**Mark Word хранит информацию, связанную с объектами и блокировками**, когда этот объект используется как блокировка с помощью ключевого слова `synchronized`, все операции, связанные с этой блокировкой, зависят от Mark Word. Длина Mark Word в 32-битной JVM составляет 32 бита, а в 64-битной JVM — 64 бита. В зависимости от состояния блокировки Mark Word хранит различные данные. В 32-битной JVM данные хранятся следующим образом:

![](D:\git-my-flink-workspace\guage-notes\images\jvm\1645172749(1).jpg)

## 42. Типы индексов в MySQL

В настоящее время в MySQL используются следующие основные типы индексов: FULLTEXT, HASH, BTREE, RTREE.

### 1) FULLTEXT

Это полнотекстовый индекс, который поддерживается только движком MyISAM. Он может использоваться при создании таблицы (`CREATE TABLE`), изменения таблицы (`ALTER TABLE`) и создании индекса (`CREATE INDEX`). Однако полнотекстовый индекс можно создать только для столбцов типа `CHAR`, `VARCHAR` и `TEXT`. Полнотекстовый индекс был создан для решения проблемы низкой производительности запросов вида `WHERE name LIKE "%word%"` для текстовых данных.

### 2) HASHИндекс типа HASH благодаря своей уникальности (почти 100%) и структуре, похожей на пары ключ-значение, хорошо подходит для использования в качестве индекса.
Индекс типа HASH позволяет сразу находить нужное значение, не требуя пошагового поиска, как это делает дерево, поэтому он имеет очень высокую эффективность. Однако эта эффективность имеет свои условия: она проявляется только при использовании операторов "= " и "IN", а для диапазонных запросов, сортировки и составных индексов эффективность остаётся невысокой.### 3) BTREE

Индекс типа BTREE представляет собой структуру данных в виде дерева, где значения индекса хранятся согласно определённому алгоритму. При каждом запросе поиск начинается с корневого узла (root), затем последовательно проходит через узлы (nodes), чтобы получить листовой узел (leaf). Это наиболее часто используемый тип индекса в MySQL.

### 4) RTREE

Индекс типа RTREE используется крайне редко в MySQL и поддерживает только тип данных geometry. Поддерживают его только несколько движков: MyISAM, BDb, InnoDb, NDb и Archive. Относительно индекса типа BTREE, RTREE имеет преимущество в диапазонных запросах.

## 43. Описание структуры B+ дерева

B+ дерево является модификацией B дерева, **все данные хранятся в листовых узлах**, а листовые узлы соединены между собой **указателями в порядке следования**.

**Нелистовые узлы содержат все индексируемые поля**, а информация, связанная с записями, хранится в листовых узлах.

**Все листовые узлы дерева образуют упорядоченный список**, который можно проходить в порядке ключевых полей.

## 44. Основные различия между B+ деревом и B- деревом- Внутренние узлы B-дерева содержат данные; в то время как внутренние узлы B+ дерева не содержат данных и используются только как индексы, данные же хранятся в листовых узлах.
- Листовые узлы B+ дерева соединены между собой указателями в виде связного списка, в то время как B-дерево этого не делает.
- В процессе поиска B-дерево завершается после нахождения конкретного значения, тогда как B+ дерево требует поиска через индекс до получения данных из листового узла.
- Каждое ключевое значение может встречаться только один раз в одном узле B-дерева, тогда как в B+ дереве ключевое значение может встречаться несколько раз.
- У листовых узлов B-дерева нет указателей, тогда как у листовых узлов B+ дерева есть двунаправленные указатели, что позволяет удобно выполнять запросы на интервалы.## 45. Подробности реализации synchronized и lock

Операционная система предоставляет: монитор механизм (Java реализуется на C++)

- **синхронизированные методы и блоки кода реализованы с помощью монитора**, каждый объект связан с одним монитором.
- Синхронизированные методы реализуются с помощью установки флага acc_synchronized в access_flag, а синхронизированные блоки кода реализуются с помощью инструкций monitorenter и monitorexit. Выполнение этих операций осуществляется JVM путём вызова операционной системы для использования примитивов мьютекса **mutex**, при этом заблокированные потоки приостанавливаются и ожидают перезапуска, что приводит к постоянному переходу между "пользовательским" и "ядром" состояниями, что негативно влияет на производительность.

### 1) Функции synchronized

Атомарность: synchronized гарантирует, что операции внутри блока кода являются атомарными.
Видимость: synchronized гарантирует видимость (путём "синхронизации переменной в памяти основного процесса перед выполнением unlock").
Порядок выполнения: synchronized гарантирует порядок выполнения (путём "того факта, что в одно и то же время только один поток может выполнять lock для одной переменной").

### 2) Использование synchronizedСинхронизация экземплярного метода: добавляет блокировку к текущему экземпляру объекта.
Синхронизация статического метода: добавляет блокировку к объекту типа `Class`.
Синхронизация блока кода: добавляет блокировку к объекту, указанному в скобках `synchronized`.### 3) Реализация

- Синхронизированные методы и синхронизированные блоки кода реализуются с помощью монитора. Каждый объект связан с одним монитором.
- Синхронизация методов осуществляется с помощью флагов доступа `access_flag`, а синхронизированные блоки кода реализуются с помощью инструкций `monitorenter` и `monitorexit`. Выполнение этих инструкций JVM осуществляет через вызов операционной системы, используя примитив мьютекс `mutex` (вызов `pthread_mutex_lock` операционной системы для блокировки мьютекса). При этом заблокированный поток приостанавливается и ждет перезапуска, что приводит к постоянному переключению между "пользовательским" и "ядерным" состояниями, что негативно влияет на производительность.
1. JVM использует вход и выход из объекта монитора для реализации синхронизации методов и блоков кода.Синхронизация уровня метода является неявной, то есть не требует контроля через байт-кодовые инструкции. Она реализуется в процессе вызова и завершения метода. JVM может отличить синхронизированный метод от обычного, анализируя структуру метода (method_info Structure) в константном пуле метода с помощью **ACCESS SYNCHRONIZED** флага доступа. При вызове метода, вызывающая инструкция проверяет, установлен ли этот флаг. Если он установлен, выполняющий поток получает владение монитором (виртуальная машина называет это "монитором"), затем выполняет метод, а после завершения метода (независимо от того, завершился ли он нормально или нет) освобождает монитор.**Синхронизация блока кода осуществляется с помощью байт-кодовых инструкций monitorenter и monitorexit**. Эти инструкции расположены в начале и конце синхронизированного блока кода соответственно. Когда JVM выполняет инструкцию monitorenter, текущий поток пытается получить владение объектом монитора. Если монитор не заблокирован или уже заблокирован текущим потоком, счетчик блокировки увеличивается на 1. При выполнении инструкции monitorexit счетчик блокировки уменьшается на 1. Когда счетчик блокировки становится равным нулю, монитор освобождается. Если поток не может получить владение монитором, он переходит в состояние ожидания до тех пор, пока другой поток не освободит монитор.

Важно отметить:

**synchronized является рекурсивно-входящим**, поэтому он не блокирует сам себя.
**Если один поток уже владеет монитором, другие потоки, пытающиеся получить этот монитор, будут заблокированы.**

Что касается флагов ACC_SYNCHRONIZED, monitorenter и monitorexit, можно рассмотреть следующий декомпилированный код:

```java
public class SynchronizedDemo {
    public synchronized void f() {    // Это синхронизированный метод
        System.out.println("Hello world");
    }
    public void g() {
        synchronized (this) {		// Это синхронизированный блок кода
            System.out.println("Hello world");
        }
    }
    public static void main(String[] args) {

    }
}

Используя javap -verbose SynchronizedDemo, мы можем получить следующий декомпилированный код:

Мы видим, что для синхронизированных методов декомпилятор выдает флаг ACC_SYNCHRONIZED, а для синхронизированных блоков кода — инструкции monitorenter и monitorexit.

На приведенном выше рисунке видно:

  1. Для синхронизированных методов декомпилятор выдает байт-код с флагом ACC_SYNCHRONIZED.
  2. Для синхронизированных блоков кода декомпилятор выдает байт-код с инструкциями monitorenter и monitorexit. Таким образом, мы можем сделать вывод:
  3. Область действия synchronized различна, а также различаются принципы реализации на уровне JVM.
  4. Кодовые блоки synchronized реализуются с помощью команд monitorenter и monitorexit.
  5. Synchronized методы реализуются с помощью метки ACC_SYNCHRONIZED.

4) Понимание объектного заголовка в Java

В JVM объекты в памяти размещаются в трех областях: заголовок объекта, экземплярные данные и заполнение.

Экземплярные переменные: хранят информацию о данных атрибутов класса, включая атрибуты родительского класса. В случае массива, часть экземпляра также включает длину массива. Эта часть памяти выравнивается по 4 байта.

Заполнение: поскольку JVM требует, чтобы начальный адрес объекта был кратен 8 байтам, заполнение не обязательно существует и используется только для выравнивания по байтам.Объектный заголовок HotSpot JVM состоит из двух частей информации: первая часть используется для хранения данных, связанных с работой объекта, таких как хэш-код, возраст поколения сборки мусора и информация о блокировках. Длина этой части данных составляет 32 бита для 32-битной и 64 бита для 64-битной версий JVM. Официально эта часть называется Mark Word. Вторая часть используется для хранения указателя на данные типа объекта. Если это объект-массив, то есть еще одна часть, которая хранит длину массива.

Битность JVM Структура заголовка объекта Описание
32/64 бит Mark Word Хранит хэш-код объекта, возраст поколения сборки мусора, информацию о блокировках и т.д.
32/64 бит Указатель на данные типа объекта Указатель на данные типа объекта
32/64 бит Длина массива Если это объект-массив, то есть эта часть, в противном случае нет

Поскольку информация в заголовке объекта не связана с данными, определенными самим объектом, это дополнительная стоимость хранения. Поэтому, с учетом эффективности использования памяти JVM, Mark Word был спроектирован как непостоянная структура данных, чтобы иметь возможность хранить больше полезных данных. Он может использовать свое хранилище повторно в зависимости от состояния самого объекта.

46. Логи undo в MySQL

Логи undo содержат старые данные, логи redo содержат новые данные после изменения.

Логи undo содержат логи до восстановления, логи redo содержат логи после восстановления. Для обеспечения атомарности транзакций перед любыми изменениями данных производится их резервное копирование в Undo Log, после чего данные могут быть изменены. В случае возникновения ошибки или выполнения пользователем команды ROLLBACK система может восстановить данные до состояния, которое было до начала транзакции, используя резервные копии из Undo Log. В отличие от redo log, на диске нет отдельного файла Undo Log; он хранится внутри специального сегмента (segment) базы данных, который называется undo-сегментом (undo segment), и этот сегмент находится в общем пространстве таблиц. InnoDB для каждой строки реализует три скрытых поля:

  • 6 байт идентификатора транзакции (DB_TRX_ID)
  • OnClickListener 7 байт указателя отката (DB_ROLL_PTR)
  • Скрытый идентификатор

47. Redo log журнал в MySQL

48. Что такое теория CAP?

Теория CAP также известна как принцип CAP, который гласит, что в распределённой системе можно обеспечить одновременно два из трёх следующих свойств: согласованность (Consistency), доступность (Availability) и устойчивость к разделению (Partition tolerance). Согласованность (Consistency) (все узлы имеют одинаковые данные в любое время) Доступность (Availability) (гарантируется ответ на каждый запрос, независимо от того, успешен он или нет) Устойчивость к разделению (Partition tolerance) (потеря или сбой любого количества информации в системе не влияют на её дальнейшую работу)

49. Обзор протокола HTTP

1) Краткое описание протокола HTTP

Протокол HTTP — это Hyper Text Transfer Protocol (протокол передачи гипертекста), используемый для передачи гипертекста с сервера World Wide Web (WWW) на локальный браузер. HTTP — это протокол передачи данных, основанный на протоколе TCP/IP (HTML-файлы, изображения, результаты запросов и т.д.).

2) Модель уровней HTTP

3) Протоколы уровней модели TCP/IP

В модели TCP/IP протоколы, соответствующие каждому уровню, показаны на следующем рисунке. HTTP является протоколом прикладного уровня.

4) Структура протокола HTTP

5) Методы HTTP

Согласно стандарту HTTP, запросы могут использовать различные методы.

HTTP 1.0 определил три метода: GET, POST и HEAD.

HTTP 1.1 добавил пять новых методов: OPTIONS, PUT, DELETE, TRACE и CONNECT.

Основные методы:

Метод Описание
GET Получение данных (например, получения страницы index.html)
POST Загрузка/создание файла (создаст новые данные)
PUT Сохранение данных (обновление/перезапись файла, изображения и т.д., не создаёт новых данных)
DELETE Удаление

6) HTTP состояния

Коды состояния состоят из трех цифр, первая цифра определяет категорию ответа, всего пять категорий:| 1xx | Информационные сообщения — указывают, что запрос был принят и обрабатывается дальше | | ----|--------------------------------------------------------------------------------------------| | 2xx | Успешный — указывает, что запрос был успешно принят, понят и выполнен | | 3xx | Перенаправление — для завершения запроса требуется выполнение дополнительных действий | | 4xx | Ошибки клиента — запрос содержит синтаксическую ошибку или не может быть выполнен | | 5xx | Ошибки сервера — сервер не может выполнить легитимный запрос |Часто используемые коды состояния 200 Запрос клиента успешно выполнен 301 Постоянное перенаправление. Поисковые системы удаляют исходный адрес и сохраняют перенаправленный адрес 302 Временное перенаправление. Аналогично 301, но ресурс временно перемещён. Клиент должен продолжать использовать оригинальный URI 304 Кэшированный файл не истёк, его можно использовать дальше, без необходимости получения из сервера 400 Запрос клиента содержит синтаксическую ошибку, которую сервер не может понять 401 Запрос не авторизован, этот код состояния должен использоваться вместе с заголовком WWW-Authenticate 403 Сервер получил запрос, но отказался предоставить услугу 404 Запрошенный ресурс не существует 413 Сущность запроса слишком велика. Сервер не может обработать запрос, так как сущность запроса слишком велика, превышает возможности сервера. 500 Внутренняя ошибка сервера. Сервер столкнулся с ошибкой и не может выполнить запрос. (Забыли выключить брандмауэр) 501 Не реализовано. Сервер не имеет возможности выполнить запрос. Например, сервер может вернуть этот код, если он не может распознать метод запроса. 502 Ошибка шлюза. Сервер работает в качестве шлюза или прокси и получил недействительный ответ от сервера-источника. 503 Услуга недоступна. Сервер временно недоступен (из-за перегрузки или планового обслуживания). Обычно это временное состояние.504 (Gateway Timeout) Сервер выполняет роль шлюза или прокси, но не получил ответ от исходного сервера вовремя.### 7) Подробности HTTP-ответа. Часто используемые HTTP-заголовки Location Сервер использует этот заголовок, чтобы сообщить браузеру, куда перейти. Server Сервер использует этот заголовок, чтобы сообщить браузеру модель сервера. Content-Encoding Сервер использует этот заголовок, чтобы сообщить браузеру, какой сжатый формат используется для данных. Content-Length Сервер использует этот заголовок, чтобы сообщить браузеру длину возвращаемых данных. Content-Language Сервер использует этот заголовок, чтобы сообщить браузеру язык контента. Content-Type Сервер использует этот заголовок, чтобы сообщить браузеру тип возвращаемых данных. Refresh Сервер использует этот заголовок, чтобы сообщить браузеру о необходимости периодического обновления. Content-Disposition Сервер использует этот заголовок, чтобы сообщить браузеру о том, что данные должны быть скачаны. Transfer-Encoding Сервер использует этот заголовок, чтобы сообщить браузеру, что данные отправляются в блоках. Expires -1 Управляет кэшированием браузера.

50. Подробное объяснение базовых принципов MySQL MVCC

Основные моменты для запоминания- MVCC (Multi-Version Concurrency Control), многовersionная система управления параллельными операциями

  • Метод, используемый в базах данных для управления параллельными операциями
  • MVCC действует только при уровнях транзакционной изоляции "Чтение уже подтвержденных" и "Повторяемое чтение"
  • Реализуется с помощью версионной цепочки Undo-журналов и консистентного представления ReadView****Многовersionная система управления параллельными операциями (MVCC) используется в базах данных для управления параллельными операциями, обеспечивая параллельный доступ к данным. В MySQL MVCC действует только при уровнях транзакционной изоляции "Чтение уже подтвержденных (Read Committed)" и "Повторяемое чтение (Repeatable Read)". Реализуется это с помощью версионной цепочки Undo-журналов и консистентного представления ReadView. MVCC позволяет SELECT-запросам находить конкретную версию данных в версионной цепочке и возвращать данные из этой версии.

Сначала важно понять, что в MySQL для наших таблиц автоматически добавляются три скрытых поля:

DB_ROW_ID: ID строки, MySQL требует от каждого таблицы наличия первичного ключа. Если ключ не указан, будет автоматически выбран первый уникальный индекс без NULL значений. Если такой индекс не найден, будет создан уникальный ID в DB_ROW_ID (этот столбец имеет небольшое отношение к MVCC); DB_TRX_ID: ID транзакции, который записывает ID текущей транзакции при выполнении операций INSERT или UPDATE (DELETE рассматривается как специальный случай UPDATE); DB_ROLL_PTR: указатель отката, который позволяет связывать различные версии в цепочку версий. Это аналогично указателю next в связном списке.

Решения для обеспечения атомарности API в условиях высокой конкуренции### 1) Сценарии атомарности API

В наших реальных системах есть много операций, которые должны генерировать одинаковый эффект или возвращать одинаковый результат, независимо от того, сколько раз они выполняются.

Например,

  1. Передняя часть повторно отправляет выбранные данные, и серверная часть должна генерировать только один ответ для этих данных;
  2. Мы отправляем запрос на оплату, и счет пользователя должен быть списан только один раз, даже если произойдет повторная отправка из-за проблем сети или багов системы;
  3. Отправка сообщений также должна происходить только один раз, иначе пользователи могут получить несколько одинаковых сообщений;
  4. Создание бизнес-заказа должно происходить только один раз при одном бизнес-запросе, иначе могут возникнуть серьезные проблемы.

2) Концепция атомарности (idempotence) в интерфейсах

Пусть операция будет атомарной, если её выполнение сколько угодно раз приведёт к одинаковому эффекту и возвращаемому результату.### 3) Техническое решение — Операция выборки: одиночный запрос и множественные запросы при неизменности данных дают одинаковый результат. Выборка является атомарной операцией;

  • Операция удаления: удаление также является атомарной операцией, одно или множественное удаление приводят к тому, что данные удаляются. (Обратите внимание, что результат может отличаться: если удалённых данных не существует, возвращается 0, если удалено несколько записей, возвращаются несколько результатов);

  • Уникальный индекс, предотвращает создание грязных данных. Например, в системе платежей Alipay есть счёт клиента, и каждый клиент может иметь только один счёт. Как предотвратить создание нескольких счетов для одного клиента? Добавляем уникальный индекс на поле ID клиента. Таким образом, успешное создание записи означает, что у клиента уже есть один счёт. Ключевые моменты: уникальный индекс или уникальное сочетание индексов используются для предотвращения создания грязных данных (если таблица имеет уникальный индекс, и при параллельном добавлении новых данных возникает ошибка, повторный запрос покажет, что данные уже существуют, и можно вернуть результат);

  • Механизм токена, предотвращает повторное отправление формы. Требования бизнеса: данные формы могут быть отправлены только один раз.Причины: повторное нажатие кнопки или повторная отправка данных через сеть или Nginx могут привести к повторному отправлению данных. Решение: в кластерной среде используется токен, хранящийся в Redis (Redis работает в одном потоке, поэтому запросы обрабатываются последовательно); в однопроцессной среде используется токен, хранящийся в Redis или в памяти JVM. Процесс обработки: 1. Перед отправкой данных необходимо получить токен от сервера, токен сохраняется в Redis или памяти JVM, и устанавливается время его действия; 2. После отправки данных сервер проверяет токен и удаляет его, генерируя новый токен. Характеристики токена: требуется получение, одноразовая активность, возможность ограничения скорости. Внимание: для проверки токена в Redis следует использовать операцию удаления, успешное удаление означает прохождение проверки токена, использование select + delete может вызвать проблемы при параллельной работе, что не рекомендуется;

  • Пессимистический блокировщик — блокировка данных при получении. select * from table_xxx where id='xxx' for update; Внимание: поле id должно быть первичным ключом или уникальным индексом, иначе это будет блокировка всей таблицы, что может привести к серьёзным проблемам. Обычно используется вместе с транзакциями, время блокировки может быть длительным, используйте в зависимости от конкретной ситуации;- Оптимистический блокировщик — блокировка таблицы происходит только при обновлении данных, в остальное время блокировка не применяется, поэтому эффективность выше, чем у пессимистического блокировщика. Реализация оптимистического блокировщика может быть различной, используя версию или другие условия состояния: 1. Через номер версии: update table_xxx set name=#name#, version=version+1 where version=#version#; 2. Ограничение условием при обновлении таблицы:```sql UPDATE table_xxx SET avai_amount = avai_amount - #subAmount# WHERE avai_amount - #subAmount# >= 0 AND quality - #subQuality# >= 0;


Требования: качество должно быть больше или равно `#subQuality#`. В этом случае подходят ситуации, где не требуется использование версионного номера, а только проверка целостности данных перед обновлением. Подходит для моделей инвентаризации, где необходимо вычесть или вернуть количество, обеспечивая более высокую производительность.- **Распределённый блокировщик** — если это распределённая система, создание глобального уникального индекса может быть затруднено. Например, уникальное поле может быть неопределённым. В таком случае можно использовать распределённый блокировщик, используя третью сторону (например, Redis или Zookeeper). При вставке или обновлении данных в бизнес-системе получается распределённая блокировка, после чего выполняется операция, а затем блокировка освобождается. Это фактически представляет собой применение идеи блокировки многопоточной системы к распределённой системе. Ключевые моменты: если какой-то длинный процесс требует выполнения без параллелизма, можно получить распределённую блокировку до начала процесса по какому-либо маркеру (например, ID пользователя + суффикс). Другие процессы, пытаясь получить блокировку, будут заблокированы, то есть в одно время только один процесс может успешно выполниться. После завершения процесса блокировка должна быть освобождена (распределённая блокировка предоставляется третьей стороной).- **SELECT + INSERT** — для фоновых систем с низким уровнем параллелизма или задач JOB, чтобы поддерживать идемпотентность и возможность повторного выполнения, простое решение заключается в том, чтобы сначала выполнить запрос на ключевые данные, проверить, был ли процесс уже выполнен, и только затем выполнять бизнес-логику. Обратите внимание: этот метод не следует использовать для основных высокопараллельных процессов.

- **Идемпотентность машины состояний** — при проектировании бизнес-процессов, связанных с заявками или задачами, часто используются машины состояний (диаграммы изменения состояния). На каждом документе или задаче есть состояние, которое меняется в зависимости от различных условий. Обычно используется конечный автомат, и если машина состояний уже находится в следующем состоянии, приходящее изменение предыдущего состояния теоретически не должно быть выполнено, что гарантирует идемпотентность конечного автомата. Обратите внимание: для заказов и других документов, имеющих длительное состояние, важно глубоко понимать машину состояний, что значительно повышает способность проектирования бизнес-систем.

- **Как гарантировать идемпотентность API, предоставляемого внешним потребителям**. Например, для платежного интерфейса UnionPay: необходимо, чтобы магазин при отправке запроса на оплату прилагал источник (source) и последовательный номер (seq).    `source + seq` должны быть уникальными в базе данных, чтобы предотвратить повторные платежи (при параллелизме, обрабатывается только один запрос). Основное условие для предоставления интерфейсов для поддержки идемпотентных вызовов заключается в том, что интерфейсу должны передаваться два обязательных поля: источник (source) и последовательный номер источника (seq). Эти два поля должны иметь уникальный составной индекс в системе поставщика. Таким образом, когда третья сторона производит вызов, она сначала проверяет, был ли этот вызов уже обработан в своей системе, и возвращает соответствующий результат обработки. Если вызов еще не был обработан, он обрабатывается, а затем возвращается результат.

Важно отметить, что для обеспечения удобства идемпотентности, всегда следует сначала проверять, был ли уже обработан данный вызов. Прямое добавление вызова без предварительной проверки может привести к ошибкам, хотя фактически вызов уже был обработан.

## 52. Четырёхуровневая модель TCP/IP: основные протоколы каждого уровня

![](D:\git-my-flink-workspace\guage-notes\images\http\1645664982(1).jpg)

**Протоколы прикладного уровня**

1) HTTP: гипертекстовый протокол передачи, основанный на TCP, используется для передачи гипертекста с WWW-сервера в локальный браузер. Он позволяет браузеру работать более эффективно и уменьшает сетевые передачи.2) SMTP: простой протокол передачи электронной почты, представляющий собой набор правил для передачи электронной почты от источника до назначения. Он контролирует методы пересылки писем.

3) SNMP: простой протокол управления сетью, состоящий из набора стандартов управления сетью, включая протокол прикладного уровня, модель базы данных и набор объектов ресурсов.

4) FTP: протокол передачи файлов, используемый для двусторонней передачи файлов через Интернет. Это также приложение.

5) Telnet: стандартный протокол удалённого доступа Internet, который предоставляет пользователям возможность выполнять работу на удалённом сервере с локального компьютера. В терминальном клиенте используется программа Telnet для подключения к серверу.

6) SSH: безопасный протокол внешнего шифрования, основанный на уровне приложений и транспортном уровне. SSH — это наиболее надёжный протокол, обеспечивающий безопасность для удалённого входа и других сетевых служб.

7) NFS: сетевой файловый системный протокол, один из поддерживаемых FreeBSD файловых систем, который позволяет компьютерам в сети совместно использовать ресурсы через TCP/IP.

## 53. Отличия между synchronized и Lock- Во-первых, `synchronized` — это встроенное ключевое слово Java, а `Lock` — это класс Java;
- **`synchronized` не может определить, удалось ли получить блокировку, а `Lock` может это сделать;**
- **`synchronized` автоматически освобождает блокировку** (если поток A завершил выполнение синхронного кода, блокировка будет освобождена; если во время выполнения потока B произошла ошибка, блокировка также будет освобождена), а `Lock` требует освобождения блокировки в `finally` (метод `unlock()` освобождает блокировку), иначе легко возникнет блокировка потока;
- При использовании ключевого слова `synchronized` два потока A и B, если поток A получил блокировку, поток B будет ждать. Если поток A заблокирован, поток B будет продолжать ждать, пока поток A не освободит блокировку. Однако при использовании `Lock` потоки могут не ждать, если они не смогут получить блокировку;
- `synchronized` не может быть прерван, блокировка является повторно захватываемой и неприоритетной, а `Lock` является повторно захватываемой, проверяемой и приоритетной (оба могут быть);
- `Lock` подходит для большого количества синхронизированных операций, а `synchronized` подходит для небольшого количиства синхронизированных операций.## 54. redis и zookeeper распределённых блоков的区别Основное различие между распределёнными блоками Redis и ZooKeeper заключается в выборе между высокой доступностью и сильной согласованностью. Высокая производительность Redis намного превышает ZooKeeper, но при этом она значительно уступает ему по надёжности.

### 1) Распределённый блок Redis

1. Redis полностью основан на оперативной памяти.

2. Redis использует однопоточную модель с многоканальным вводом/выводом, что позволяет снизить затраты на создание множества потоков и избежать ненужных переключений контекста и конкуренции за ресурсы, что приводит к увеличению стоимости блока.

3. Использование хеш-таблиц на протяжении всего процесса.

### 2) Распределённый блок ZooKeeper

Кластер ZooKeeper реализован на основе модели CP и имеет сильную согласованность. Сильная согласованность достигается с помощью протокола ZAB (ZooKeeper Atomic Broadcast), то есть атомарного протокола передачи данных ZooKeeper.

Протокол ZAB поддерживает автоматическое восстановление и атомарную передачу данных, что делает его специально разработанным для ZooKeeper протоколом согласования.

Атомарная передача данных представляет собой процесс синхронного копирования, мы можем начать с других протоколов согласования, таких как 2PC.

2PC — это протокол двухфазного подтверждения (Two-phase Commit), который можно представить следующим образом:Первая фаза: голосование (этап запроса)

**Управляющий транзакциями** сообщает каждому участнику подготовиться к подтверждению или отмене транзакции, затем начинается этап голосования, где каждый участник либо выполняет транзакцию локально, но не подтверждает её; либо сообщает управляющему своё решение: согласиться или отказаться.

Вторая фаза: выполнение (этап подтверждения)

На этом этапе управляющий принимает решение на основе результатов голосования на этапе запроса: подтвердить или отменить; управляющий уведомляет всех участников о подтверждении или отмене транзакции только тогда, когда все участники согласились на подтверждение; участники выполняют соответствующие действия после получения уведомлений от управляющего.

Проблема синхронного блокирования скрыта в протоколе 2PC, которую здесь мы должны обратить внимание.

Другие протоколы согласования включают 3PC, Paxos и т.д.; процесс протокола ZAB можно сравнить с 2PC (но ZAB является более чем половиной эффективным), но фактически он больше похож на улучшенную версию протокола Paxos, поскольку он слишком сложен, чтобы быть представленным здесь. Однако они не могут полностью решить проблему синхронного блокирования.## 55. Пять алгоритмов планирования процессов

1. **Алгоритм циклического выполнения с фиксированной продолжительностью (RR)**: выделяет каждому процессу фиксированное время выполнения, позволяя процессам выполняться в порядке их прибытия в течение одного временного слота. После завершения выполнения процесса происходит переключение на следующий процесс. Алгоритм RR не учитывает время ожидания и выполнения процессов, что делает его принудительным (preemptive) алгоритмом распределения. Преимуществом является учет как коротких, так и длинных задач; недостатком — увеличенное среднее время ожидания и высокие затраты на переключение контекста. Подходит для систем разделения времени.2. **Алгоритм первым пришел — первым обслужил (FCFS)**: выполняет процессы в порядке их прибытия, не учитывая время ожидания и выполнения. Может привести к эффекту голода (starvation). Это непрерывный (non-preemptive) алгоритм распределения. Преимуществом является справедливость и простота реализации; недостатком — невыгодность для коротких задач.

3. **Алгоритм распределения с учетом приоритетов (HPF)**: выбирает для выполнения процесс с наивысшим приоритетом из очереди ожидания.

4. **Множественный уровень обратной связи (MLFQ)**: объединяет циклическое выполнение с фиксированной продолжительностью и распределение с учетом приоритетов, разделяя процессы на различные очереди в зависимости от их приоритетов. Сначала выполняются процессы с наивысшими приоритетами, а процессы с одинаковыми приоритетами выполняются по циклическому принципу. Преимуществом является учет как коротких, так и длинных задач, хорошее время отклика и высокая применимость для различных условий работы.5. **Алгоритм с высоким коэффициентом отклика (HRRN)**: использует формулу "коэффициент отклика = (время выполнения процесса + время ожидания процесса) / время выполнения процесса" для распределения. При равном времени ожидания, задачи с меньшим временем выполнения имеют более высокий коэффициент отклика, что обеспечивает приоритет коротким задачам. Коэффициент отклика увеличивается с увеличением времени ожидания, повышая приоритет задачи и предотвращая эффект голода. Преимуществом является учет как коротких, так и длинных задач; недостатком — высокие затраты на расчет коэффициента отклика. Подходит для систем обработки заданий. ## Механизм масштабирования Redis (постепенное однопоточное масштабирование)## Принцип работы IoC в Spring, как это реализовано, как решаются циклические зависимости?

## Два потока выполняют операцию увеличения переменной i на 1, какой будет результат? Почему? Как это можно исправить?

## Концепция CAS, принцип реализации атомарных классов

## Подробная реализация synchronize, как реализуется Lock?

## Какие особенности имеет AQS?

### Введение в различные сетевые протоколы.

#### Какой протокол используется на уровне сети для DNS и почему?

#### Введение в протокол HTTPS, подробное описание процесса установки соединения SSL.

### Кодовые задачи: 
- **Перевернуть односвязный список**.
- **Копировать сложный односвязный список**.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/yangdechao_admin-guage-notes.git
git@api.gitlife.ru:oschina-mirror/yangdechao_admin-guage-notes.git
oschina-mirror
yangdechao_admin-guage-notes
yangdechao_admin-guage-notes
master