Что такое JVM, JRE и JDK?
Java Virtual Machine - это абстрактная машина. Это спецификация, которая позволяет исполнять байт-код Java (а также программы, написанные на других языках, которые также компилируются в байт-код Java) предварительно созданный из исходного текста Java-программы компилятором Java (javac).
Java Runtime Environment - минимальная (без компилятора и других средств разработки) реализация виртуальной машины (JVM), необходимая для исполнения Java-приложений. Включает в себя виртуальную машину JVM и библиотеку классов Java — Java Class Library.
Java development kit - это JRE + компилятор и библиотеки классов.
Java Virtual Machine - это абстрактная машина. Это спецификация, которая позволяет исполнять байт-код Java (а также программы, написанные на других языках, которые также компилируются в байт-код Java) предварительно созданный из исходного текста Java-программы компилятором Java (javac).
Java Runtime Environment - минимальная (без компилятора и других средств разработки) реализация виртуальной машины (JVM), необходимая для исполнения Java-приложений. Включает в себя виртуальную машину JVM и библиотеку классов Java — Java Class Library.
Java development kit - это JRE + компилятор и библиотеки классов.
Что такое Транзакция?
Транзакция - это множество операций (чтение/запись), выполняемых как единое атомарное (неделимое) действие, переводящих базу данных из одного согласованного состояния в другое.
Транзакция - это множество операций (чтение/запись), выполняемых как единое атомарное (неделимое) действие, переводящих базу данных из одного согласованного состояния в другое.
Что такое ACID?
ACID - требования к СУБД
Atomicity (Атомарность) - гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния
Consistency (Согласованность) - это требование вытекает из предыдущего и подразумевает, что в результате работы транзакции данные были допустимы. Это вопрос бизнес-логики.
Isolation (Изолированность) - во время транзакции параллельные потоки не должны оказывать влияние на её результат.
Durability (Надежность, прочность) - если пользователь получил подтверждение от системы, что транзакция выполнена, он может быть уверен, что сделанные им изменения не будут отменены из-за какого-либо сбоя.
ACID - требования к СУБД
Atomicity (Атомарность) - гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния
Consistency (Согласованность) - это требование вытекает из предыдущего и подразумевает, что в результате работы транзакции данные были допустимы. Это вопрос бизнес-логики.
Isolation (Изолированность) - во время транзакции параллельные потоки не должны оказывать влияние на её результат.
Durability (Надежность, прочность) - если пользователь получил подтверждение от системы, что транзакция выполнена, он может быть уверен, что сделанные им изменения не будут отменены из-за какого-либо сбоя.
Какие проблемы возможны при параллельном выполнении транзакций?
1. Dirty Read (Грязное чтение) - это ситуация, когда транзакция считывает данные, которые еще не были зафиксированы.
2. Lost Update (Потерянное обновление) - при одновременном изменение одного блока данных разными транзакциями теряются все изменения кроме последнего.
3. Non-Repeatable Read (Неповторяющееся чтение) - чтение происходит, когда транзакция дважды считывает одну и ту же строку и каждый раз получает разное значение.
4. Phantom Reads (Фантомное чтение) - одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.
1. Dirty Read (Грязное чтение) - это ситуация, когда транзакция считывает данные, которые еще не были зафиксированы.
2. Lost Update (Потерянное обновление) - при одновременном изменение одного блока данных разными транзакциями теряются все изменения кроме последнего.
3. Non-Repeatable Read (Неповторяющееся чтение) - чтение происходит, когда транзакция дважды считывает одну и ту же строку и каждый раз получает разное значение.
4. Phantom Reads (Фантомное чтение) - одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.
👍1
Какова структура памяти в Java?
Native Memory - вся доступная системная память.
Heap (куча) - часть native memory, выделенная для кучи. Здесь JVM хранит объекты. Это общее пространство для всех потоков приложения.
Stack (стэк) - используется для хранения локальных переменных и стека вывзовов метода.
Metaspace (метаданные) - в этой памяти хранятся метаданные классов и статические переменные. Это пространство также является общим.
CodeCache (кэш кода) - JIT-компилятор компилирует часто исполняемый код, преобраует его в нативный машинный код и кеширует для более быстрого выполнения.
Native Memory - вся доступная системная память.
Heap (куча) - часть native memory, выделенная для кучи. Здесь JVM хранит объекты. Это общее пространство для всех потоков приложения.
Stack (стэк) - используется для хранения локальных переменных и стека вывзовов метода.
Metaspace (метаданные) - в этой памяти хранятся метаданные классов и статические переменные. Это пространство также является общим.
CodeCache (кэш кода) - JIT-компилятор компилирует часто исполняемый код, преобраует его в нативный машинный код и кеширует для более быстрого выполнения.
Что такое мусор в Java и сборщик мусора?
Мусором считается объект, который больше не может быть достигнут по ссылке из какого-либо объекта. Поскольку такие объекты не используются в приложении, то их можно удалить из памяти.
В примере на картинке fruit2 может быть удален из памяти, поскольку нет ссылок.
Сборка мусора — это процесс автоматического управления памятью. Освобождение памяти (путем очистки мусора) выполняется автоматически специальным компонентом JVM — сборщиком мусора (Garbage Collector, GC). Нам, как программистам, нет необходимости вмешиваться в процесс сборки мусора.
Мусором считается объект, который больше не может быть достигнут по ссылке из какого-либо объекта. Поскольку такие объекты не используются в приложении, то их можно удалить из памяти.
В примере на картинке fruit2 может быть удален из памяти, поскольку нет ссылок.
Сборка мусора — это процесс автоматического управления памятью. Освобождение памяти (путем очистки мусора) выполняется автоматически специальным компонентом JVM — сборщиком мусора (Garbage Collector, GC). Нам, как программистам, нет необходимости вмешиваться в процесс сборки мусора.
Что такое Checked & Unchecked exception?
Java - это компилируемый язык, а значит помимо runtime (время выполнения кода) у него есть compile-time (то, что происходит во время компиляции).
Проверяемые исключения - это те исключения на которые разработчик обязан отреагировать, т.е. написать обработчики, и наличие этих обработчиков будет проверена на этапе компиляции. Код не будет скомпилирован, если какое-то проверяемое исключение не обработано, компилятор этого не допустит. (Проверяемые исключения реализуют класс Exception)
Непроверяемые исключения - это исключения, которые компилятор не требует от разработчика обработки. (Непроверяемые исключения реализуют класс RuntimeException)
Java - это компилируемый язык, а значит помимо runtime (время выполнения кода) у него есть compile-time (то, что происходит во время компиляции).
Проверяемые исключения - это те исключения на которые разработчик обязан отреагировать, т.е. написать обработчики, и наличие этих обработчиков будет проверена на этапе компиляции. Код не будет скомпилирован, если какое-то проверяемое исключение не обработано, компилятор этого не допустит. (Проверяемые исключения реализуют класс Exception)
Непроверяемые исключения - это исключения, которые компилятор не требует от разработчика обработки. (Непроверяемые исключения реализуют класс RuntimeException)
Что будет, если переопределить equals() не переопределяя hashCode()? 🤔
Классы и методы, которые используют правила данного контракта могут некорректно работать, потому что перед тем как сравнить объекты по equals всегда сравнивают/ищут с помощью hashCode. По умолчанию hashCode возвращает уникальное значение для каждого объекта, и если у одинаковых объектов будут разные hashCode сравнение до equals даже не дойдет.
Классы и методы, которые используют правила данного контракта могут некорректно работать, потому что перед тем как сравнить объекты по equals всегда сравнивают/ищут с помощью hashCode. По умолчанию hashCode возвращает уникальное значение для каждого объекта, и если у одинаковых объектов будут разные hashCode сравнение до equals даже не дойдет.
В чем разница между finalize & finally & final?
final - модификатор, который дает:
- Поля не могут быть изменены, методы переопределены;
- Классы нельзя наследовать (а значит и методы переопределить нельзя);
- Применяется только к классам, методам и полям (локальным тоже);
- Аргументы метода указанные final доступны только для чтения, при попытки изменить будет ошибка компиляции;
- final поля необходимо инициализировать сразу (присвоить явно или через конструктор), иначе ошибка;
- Если переменная содержит ссылку на объект и объявлена как final, то содержимое объекта можно менять, а ссылку переменной нельзя (это же справедливо и для массивов)
* если класс final и abstract (взаимоисключающие понятия) возникнет ошибка.
finally - блок в try-catch-finally, который опционален и вызывается в независимости от того вылетело исключение или нет
finalize - метод в классе Object.
final - модификатор, который дает:
- Поля не могут быть изменены, методы переопределены;
- Классы нельзя наследовать (а значит и методы переопределить нельзя);
- Применяется только к классам, методам и полям (локальным тоже);
- Аргументы метода указанные final доступны только для чтения, при попытки изменить будет ошибка компиляции;
- final поля необходимо инициализировать сразу (присвоить явно или через конструктор), иначе ошибка;
- Если переменная содержит ссылку на объект и объявлена как final, то содержимое объекта можно менять, а ссылку переменной нельзя (это же справедливо и для массивов)
* если класс final и abstract (взаимоисключающие понятия) возникнет ошибка.
finally - блок в try-catch-finally, который опционален и вызывается в независимости от того вылетело исключение или нет
finalize - метод в классе Object.
В чем отличие i++ и ++i?
++i, i сначала увеличивается на 1, затем участвует в выражении.
i++, i сначала участвует в выражении, затем увеличивается на 1.
++i, i сначала увеличивается на 1, затем участвует в выражении.
i++, i сначала участвует в выражении, затем увеличивается на 1.
Что такое связывание? Как происходит связывание в Java?
Связывание (binding) - присоединение вызова метода к телу метода.
Ранее связывание (early binding) - это связывание, происходящее во время компиляции (также называется static binding). При раннем связывании тип объекта уже должен быть известен. Но так бывает не всегда, если есть иерархия наследования или общий интерфейс.
Например, если есть ссылка на базовый класс, например в качестве аргумента метода, а передается в него класс-потомок, а таких потомков может быть много. Тут компилятор сошел бы с ума, т.к. не знал бы методы какого класса вызывать. Но для разрешения этой проблемы существовал другой вид связывания.
Позднее связывание (late binding) - это связывание, которое выполняется во время выполнения программы (также называют dynamic binding или runtime binding). При позднем связывании определяется фактический тип объекта для вызова именно его метода.
Для всех методов Java используется механизм позднего связывания, если только метод не был объявлен как private Вызов private метода компилируется в инструкцию байт-кода "invokespecial", которая вызывает реализацию метода из конкретного класса, определенного в момент компиляции. Вызов метода с другим уровнем доступа компилируется в "invokevirtual", которая уже смотрит на тип объекта по ссылке в момент исполнения. Финальные неприватные методы тоже вызываются через "invokevirtual". Есть конечно еще несколько других инструкций байт-кода для вызова методов: invokedynamic, invokeinterface и invokestatic.
*Перегрузка метода - это полиморфизм во время компиляции, при котором несколько методов имеют одно и то же имя с разными параметрами или сигнатурой и разным типом возвращаемого значения. Переопределение метода - это полиморфизм среды выполнения, имеющий один и тот же метод с одинаковыми параметрами или сигнатурой, но связанный с сопоставляемыми разными классами.
Связывание (binding) - присоединение вызова метода к телу метода.
Ранее связывание (early binding) - это связывание, происходящее во время компиляции (также называется static binding). При раннем связывании тип объекта уже должен быть известен. Но так бывает не всегда, если есть иерархия наследования или общий интерфейс.
Например, если есть ссылка на базовый класс, например в качестве аргумента метода, а передается в него класс-потомок, а таких потомков может быть много. Тут компилятор сошел бы с ума, т.к. не знал бы методы какого класса вызывать. Но для разрешения этой проблемы существовал другой вид связывания.
Позднее связывание (late binding) - это связывание, которое выполняется во время выполнения программы (также называют dynamic binding или runtime binding). При позднем связывании определяется фактический тип объекта для вызова именно его метода.
Для всех методов Java используется механизм позднего связывания, если только метод не был объявлен как private Вызов private метода компилируется в инструкцию байт-кода "invokespecial", которая вызывает реализацию метода из конкретного класса, определенного в момент компиляции. Вызов метода с другим уровнем доступа компилируется в "invokevirtual", которая уже смотрит на тип объекта по ссылке в момент исполнения. Финальные неприватные методы тоже вызываются через "invokevirtual". Есть конечно еще несколько других инструкций байт-кода для вызова методов: invokedynamic, invokeinterface и invokestatic.
*Перегрузка метода - это полиморфизм во время компиляции, при котором несколько методов имеют одно и то же имя с разными параметрами или сигнатурой и разным типом возвращаемого значения. Переопределение метода - это полиморфизм среды выполнения, имеющий один и тот же метод с одинаковыми параметрами или сигнатурой, но связанный с сопоставляемыми разными классами.
Что такое оконные функции?
Оконная функция - функция, которая работает с выделенным набором строк (окон, партицией) и выполняет вычисления для этого набора строк в отдельном столбце.
Партиции для каждой оконной функции в запросе могут быть разделены по различным колонкам таблицы.
В отличии от GROUP BY количество строк не уменьшается, а возвращают столько же значений, сколько получили на вход.
Оконная функция - функция, которая работает с выделенным набором строк (окон, партицией) и выполняет вычисления для этого набора строк в отдельном столбце.
Партиции для каждой оконной функции в запросе могут быть разделены по различным колонкам таблицы.
В отличии от GROUP BY количество строк не уменьшается, а возвращают столько же значений, сколько получили на вход.
Что такое Race Condition?
Race Condition - это ситуация, когда результат выполнения программы зависит от того, в каком порядке выполняются отдельные потоки. При этом несколько потоков конкурируют за доступ к общим ресурсам, таким как переменные, массивы, файлы и т.д., и пытаются изменять их значения. Если при этом не использовать средства синхронизации, то порядок выполнения операций может быть непредсказуемым и привести к неверным результатам.
В примере мы создаем два потока, которые конкурируют за доступ к переменной count объекта класса Counter. Они вызывают метод increment(), который увеличивает значение count на единицу. Ожидаемый результат работы программы - значение count равное 200000. Однако, из-за Race Condition мы можем получить другое значение, например, 199876 или 200123, в зависимости от того, в каком порядке выполняются операции в каждом из потоков.
Чтобы избежать Race Condition в данном примере, можно использовать синхронизацию.
Race Condition - это ситуация, когда результат выполнения программы зависит от того, в каком порядке выполняются отдельные потоки. При этом несколько потоков конкурируют за доступ к общим ресурсам, таким как переменные, массивы, файлы и т.д., и пытаются изменять их значения. Если при этом не использовать средства синхронизации, то порядок выполнения операций может быть непредсказуемым и привести к неверным результатам.
В примере мы создаем два потока, которые конкурируют за доступ к переменной count объекта класса Counter. Они вызывают метод increment(), который увеличивает значение count на единицу. Ожидаемый результат работы программы - значение count равное 200000. Однако, из-за Race Condition мы можем получить другое значение, например, 199876 или 200123, в зависимости от того, в каком порядке выполняются операции в каждом из потоков.
Чтобы избежать Race Condition в данном примере, можно использовать синхронизацию.
Что такое Date Race и в чем отличие от Race Condition?
Data race (гонка данных) - это проблема, связанная с параллельным доступом нескольких потоков к общему ресурсу, при которой результат выполнения программы зависит от того, какие потоки будут выполняться и в каком порядке.
Data race может возникнуть, когда два или более потока имеют доступ к общему ресурсу и выполняют операции чтения и записи без синхронизации, что может привести к непредсказуемым результатам.
Отличие Race Condition от Data race заключается в том, что Race Condition - это более широкое понятие, которое описывает любую ситуацию, когда результат выполнения программы зависит от порядка выполнения потоков. Data race - это один из видов Race Condition, который возникает при параллельном доступе к общим ресурсам без синхронизации.
Data race (гонка данных) - это проблема, связанная с параллельным доступом нескольких потоков к общему ресурсу, при которой результат выполнения программы зависит от того, какие потоки будут выполняться и в каком порядке.
Data race может возникнуть, когда два или более потока имеют доступ к общему ресурсу и выполняют операции чтения и записи без синхронизации, что может привести к непредсказуемым результатам.
Отличие Race Condition от Data race заключается в том, что Race Condition - это более широкое понятие, которое описывает любую ситуацию, когда результат выполнения программы зависит от порядка выполнения потоков. Data race - это один из видов Race Condition, который возникает при параллельном доступе к общим ресурсам без синхронизации.
Рассмотрим пример с банковским счетом. Допустим, у нас есть банковский счет, на котором находится 100 долларов. Мы хотим произвести две операции: пополнение счета на 50 долларов и снятие со счета 50 долларов. Для этого мы создадим два потока, каждый из которых будет выполнять одну из операций.
В данном случае, мы ожидаем, что счет будет пополнен и снят со счета по 50 долларов, что приведет к ожидаемому результату - остатку на счете в 100 долларов. Однако, из-за Race Condition мы можем получить непредсказуемый результат.
Проблема возникает из-за того, что операции счета не являются атомарными - каждая из операций состоит из нескольких инструкций. В результате, один поток может успеть выполнить только часть операции, прежде чем другой поток начнет свою операцию...
В данном случае, мы ожидаем, что счет будет пополнен и снят со счета по 50 долларов, что приведет к ожидаемому результату - остатку на счете в 100 долларов. Однако, из-за Race Condition мы можем получить непредсказуемый результат.
Проблема возникает из-за того, что операции счета не являются атомарными - каждая из операций состоит из нескольких инструкций. В результате, один поток может успеть выполнить только часть операции, прежде чем другой поток начнет свою операцию...
Например, один поток может успеть считать текущий баланс счета (100 долларов), затем другой поток может снять со счета 50 долларов, и первый поток, который должен был пополнить счет, добавит к текущему балансу 50 долларов, не учитывая того, что со счета уже были сняты 50 долларов. В результате, на счете может остаться 100 долларов, если потоки выполняются последовательно, или может быть меньше 100 долларов, если потоки выполняются параллельно.
Отличие от Data race заключается в том, что в данном случае значения переменных не перезаписываются друг другом напрямую, а зависят от порядка выполнения операций.
Отличие от Data race заключается в том, что в данном случае значения переменных не перезаписываются друг другом напрямую, а зависят от порядка выполнения операций.
