Java Interview Tasks
3.91K subscribers
185 photos
1 file
121 links
Реальные вопросы и задачи с собеседований.
Оригинальный авторский контент.
Актуальный материал.
Уровень вопросов от junior до supersenior.

Автор канала - @alexzelentsov

По рекламе: @alexzelentsov и https://telega.in/c/java_interview_tasks
Download Telegram
#concurrency #java
class A {
int a;
int b;

void m1() {
a++;
b++;
}

void m2() {

System.out.println(b);
System.out.println(a);
}
}

// пример вывода
: b=1 a=0

Методы m1 и m2 запускаются в разных потоках, одновременно, один раз каждый
Какие варианты вывода могут быть? (y,x)
(похожая задача была тут - https://t.me/java_interview_tasks/26)
(Методы thread1 и thread2 запускаются в разных потоках, одновременно, один раз каждый)

public class Test {

int x;
volatile int y;

public void thread1() {
x = 1;
y = 1;
}

public void thread2() {
System.out.println(y);
System.out.println(x);
}
}
Какие значения может напечатать код (thread1 и thread2 запускаются одновременно в разных потоках)?
#jmm #concurrency #java #java_interview_tasks
👍11
Ответ на вопрос VolatileVsFinal (https://t.me/java_interview_tasks/140) :

Тут речь идет об одном из самых интересных разрешенных сценариев JMM. Это тот факт, что volatile поле не имеет final семантики.
Это означает, что если мы публикуем ссылку объекта под гонкой, то мы можем увидеть дефолтное значение для volatile поля
Поэтому в данном случае 0 вполне можно получить.

Этот эффект можно увидеть на некоторых платформах, например AArch64:
RESULT SAMPLES FREQ
-1 1,428,517,070 91.74%
0 7,105 <0.01%
42 128,534,641 8.25%
👍16🔥7🤯31
Forwarded from xpinjection
Если вы разрабатываете на Java, то видео доклада в этом посте точно расширит ваш кругозор. Java выбирают даже не за язык, а скорее за огромную экосистему, в которой разработчики могут найти готовые решения для практически любых задач. Эту экосистему важно знать. В докладе рассматривается большой список библиотек из мира Java для решения конкретных прикладных задач.

Если вы не разрабатываете на Java, но знаете Java разработчиков, поделитесь с ними этим видео. Они точно скажут вам спасибо! :)

#Java

https://youtube.com/watch?v=ABm0KhsZJ0c&feature=share9
🔥9👍5👏1
🔍 Ответ на вопрос про сравнение объектов в Java:
Разберемся, как Java сравнивает объекты и что скрывается за методами equals() и hashCode().
У нас есть два объекта:

Object o1 = new Object();
Object o2 = new Object();
Теперь давайте посмотрим, что произойдет, если мы их сравним:

1️⃣ Сравнение ссылок (оператор ==):

System.out.println((o1 == o2)); // Выводит: false
🔸 Оператор == сравнивает адреса в памяти. Поскольку o1 и o2 — разные объекты, они находятся по разным адресам, что возвращает false.

2️⃣ Сравнение методом equals():

System.out.println(o1.equals(o2)); // Выводит: false
🔸 Метод equals() по умолчанию в классе Object работает как ==, сравнивая ссылки. Без переопределения возвращает false.

3️⃣ Сравнение значений hashCode():

System.out.println(o1.hashCode() == o2.hashCode()); // Выводит: false
🔸 Метод hashCode() вычисляет уникальное значение на основе текущего объекта (реализация может быть различна и может зависеть от платформы). Обычно для двух разных объектов значения будут уникальными.
Почитать подробнее можно тут.

💡 Итак, вывод программы:

false
false
false



✍️ В реальной практике нужно переопределять equals() и hashCode(), чтобы они отражали бизнес-логику ваших объектов.

Будьте внимательны и прописывайте правильные сравнения! 🤓



🎓 Надеюсь, это было полезно! Оставьте свои вопросы и комментарии ниже. 👇

#java #программирование #equals #hashcode #разработка
👍15🔥5🙏2
🔍 Ответ на вопрос про пропавший эксепшен:

Привет, друзья! Сегодня обсудим скрытую проблему с логированием исключений, которая часто возникает в многопоточной среде.

На первый взгляд все кажется довольно обычным: мы отправляем задачу на выполнение, которая вызывает метод logString с null значением. Это должно вызвать NullPointerException.

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

🔎 Объяснение:

Исключения в Java, возникающие в потоке, обрабатываются контекстом этого потока.
В случае использования ExecutorService.submit(...), если задача выбрасывает исключение, оно остается незамеченным, потому что submit возвращает Future, который просто тихо удаляет это исключение.
Если вы не вызываете методы get() у Future и не обрабатываете возможное исключение, вы его просто не увидите.
💡 Как это исправить? Чтобы исключение стало видимым, можно сделать следующее:

public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(() -> logString(null));

try {
future.get(); // Обрабатываем возможное исключение
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); // Выводим исключение в логи
} finally {
executorService.shutdown();
}
}
📌 В этом изменении future.get() либо вернёт результат, либо выбросит ExecutionException, если что-то пошло не так, позволяя вам логировать и обрабатывать ситуацию корректно.

👨‍💻 Вывод: Будьте внимательны при работе с многопоточностью. Убедитесь, что вы корректно обрабатываете возможные исключения, особенно при использовании ExecutorService.



🎓 Надеюсь, это было полезно! Оставьте свои вопросы и комментарии ниже. 👇

Подписывайтесь, чтобы не пропустить важные советы и приемы! 🔥

#java #многопоточность #исключения #программирование #лучшиепрактики
🔥144👍4🙏1
🔍 Ответ на вопрос про volatile и массивы в Java:

📌 Многие разработчики могут ошибочно полагать, что при объявлении массива volatile все его элементы также будут обладать свойствами volatile. Однако это не так!
Пример выше как раз демонстрирует эту особенность.
🔎 Объяснение:
volatile int[] arr делает переменную arr ссылкой volatile. Это означает, что любые изменения ссылки на массив будут видны другим потокам.
Однако элементы массива не наследуют volatile-свойство. Таким образом, arr[0] и arr[1] не имеют гарантий видимости друг для друга.

Ставьте лайк , если нашли это полезным и задавайте свои вопросы и комментарии ниже для получения дополнительных знаний! 🚀

#java #многопоточность #volatile #программирование
🔥9👍43👎1👏1🙏1🐳1
🔍 Ответ на задачу про то, как Java выбирает перегрузку метода?

🚀🚀🚀Когда вы вызываете метод в Java, который имеет несколько перегруженных вариантов, компилятор должен решить, какой из них использовать. Давайте разберёмся, как он это делает на примере вызова метода printFor(42).

Вот правила, которыми руководствуется компилятор:

🚀 Точный тип: Ищет метод с точным совпадением типа аргумента. У нас его нет для int, так как метода printFor(int) нет.

🚀 Примитивное расширение (widening): Далее проверяется, можно ли расширить примитивный тип. 42 (int) может быть преобразован в long, и метод printFor(long) подходит.

🚀 Автоупаковка (boxing): Если расширение невозможно, оценивается автоупаковка. int может стать Integer, что делает метод printFor(Integer) возможным, но менее предпочтительным, чем printFor(long).

🚀 Varargs (массив произвольной длины): Как запасной вариант, компилятор рассматривает использование varargs. Метод printFor(int...) подходит, но также менее предпочтителен.

🚀 Автоупаковка в Object: Ещё менее специфичный вариант — преобразование в Integer и затем в Object для printFor(Object).

🔗🔗 🔗 В итоге, компилятор выбирает printFor(long), потому что расширение примитивного типа более предпочтительно, чем автоупаковка и varargs. Это позволяет Java эффективно и предсказуемо обрабатывать вызовы методов!

🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇

#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
1👍23🔥53
🔍 Ответ на задачу про распределение монет по кошелькам
⚠️Это задача на метод stars&bars. если в условии есть упоминание, что кошельки не должны быть пустыми, то нам нужно заранее положить по одной монетке в каждый кошелек (иначе в ответе будут случаи, где некоторые кошельки пустые): 12 - 5 = 7
⚠️Теперь мы имеем 7 монет которые нужно распределить в 5 кошельков. Для этого возьмем 4 перегордки, (они поделят наши монетки на 5 частей("кошельков")). Выглядит пример так: 💰|💰💰|💰 |💰💰|💰

⚠️В общей сумме имеем 7+4 = 11 позиций, в котором нужно рассчитать количество перестановок перегородок, а это C(4 ; 11) = (11×10×9×8)/4×3×2×1 = 330
Ответ: 330 способов

🚀Если вам понравилось это объяснение, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
🚀🚀 Если хотите больше таких задач ставьте 🔥 к этому посту.

#Combinations #Combinatorics #MathChallenge #java_interview_tasks
👍12🔥32👎1
🔍 Ответ на задачу про то, как Java выбирает перегрузку метода с null?

В Java, когда вы вызываете перегруженный метод с аргументом null, компилятор должен решить, какую версию метода использовать. Давайте разберём конкретный пример с вызовом printFor(null).

👉 Как компилятор принимает решение?

👉👉Когда мы передаём null как аргумент, Java ищет наиболее специфичный метод, который может быть вызван. В этом конкретном случае, null может быть преобразован как в String, так и в Object, поскольку String является подтипом (наследником) Object.

👉👉Специфичность типа: Согласно правилам Java, если возможны несколько перегруженных методов, компилятор выбирает тот, чьё требование более специфично. Поскольку String является более специфичной версией Object, метод printFor(String o) будет выбран.

🔗 В итоге, когда вызывается printFor(null), на консоль будет выведено "String".

Такие правила выбора метода помогают Java обрабатывать вызовы предсказуемо и логично, даже с неопределёнными значениями, как null!

🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇

#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
🔥15👍611👏1🐳1
🔍 Ответ на задачу о ConcurrentHashMap и атомарности

Одно из часто обсуждаемых свойств ConcurrentHashMap — это ее потокобезопасность в отношении методов put и get. ConcurrentHashMap гарантирует атомарность операций put и get, что значит, что каждое из этих действий выполняется полностью или не выполняется вовсе, и они могут безопасно выполняться одновременно из разных потоков.

⚡️Однако важно помнить, что эта гарантия распространяется только на сами операции put и get, но не на атомарность действий по отношению к вложенным объектам. В нашем случае, если мы извлекаем список из мапы и затем изменяем его, эти изменения не защищены от состояния гонки. Как было показано в предыдущей задаче, два потока могут создать и модифицировать один и тот же список, приводя к непредсказуемым результатам.

⚡️⚡️Поэтому при работе с ConcurrentHashMap, когда объекты, хранящиеся в мапе, также должны быть потокобезопасными, следует дополнительно обеспечивать синхронизацию либо использовать другие потокобезопасные структуры данных.

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

/*
Solves the race with putIfAbsent
*/

void addCorrect(String key, String val) {
List<String> list = map.get(key);
if (list == null) {
list = Collections.synchronizedList(new ArrayList<>());
List<String> exist = map.putIfAbsent(key, list);
if (exist != null) {
list = exist;
}
}
list.add(val);
}


/*
Solves the race with computeIfAbsent.
*/

 void addCorrect8(String key, String val) {
List<String> list = map.computeIfAbsent(key,
k -> Collections.synchronizedList(new ArrayList<>()));
list.add(val);
}


🎓 Понравилась тема про потокобезопасность в Java? Ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!

#ConcurrentHashMap #Java #Concurrency #Atomicity #java_interview_tasks
👍19🔥42👏1
🔍 Ответ на задачу про checkThenReact и состояние гонки:

В этом примере метода checkThenReact() описывается ситуация типичной проблемы конкурентного программирования, известной как "состояние гонки". Суть проблемы заключается в том, что несколько потоков (в данном случае actor1() и actor2()) могут одновременно проверить и изменить общее состояние, здесь представляемое переменной flag.

Возможные решения для устранения состояния гонки:
Синхронизация:

Заключите операцию проверки и изменения flag в блок синхронизации:
private synchronized boolean checkThenReact() {
if (flag) {
flag = false;
return true;
} else {
return false;
}
}

Использование AtomicBoolean:

Замена boolean на AtomicBoolean и использование атомарных операций. Например:

private final AtomicBoolean flag = new AtomicBoolean(true);

private boolean checkThenReact() {
return flag.compareAndSet(true, false);
}

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

🎓Если вам интересны темы конкурентности и потокобезопасности, ставьте лайк, подписывайтесь и оставляйте комментарии с вашими вопросами и переживаниями!

#Concurrency #RaceCondition #Synchronization #AtomicOperations #java_interview_tasks
👍16🔥31👌1
🔍 Ответ на задачу про JMM и особенности volatile полей

Данная задача подчеркивает одно из потенциально неожиданных поведений модели памяти Java (Java Memory Model - JMM), связанное с volatile полями. Конкретно, она касается разницы между volatile и final в контексте гарантий видимости и порядка инициализации.

⚠️ Ключевые моменты volatilе и final:

⚡️⚡️volatile гарантирует видимость изменений в переменной между потоками. Однако оно не гарантирует, что инициализация объекта до первой публикации будет выполнена полностью.
⚡️⚡️final гарантирует, что значение поля после его инициализации не изменяется, и другие потоки, получившие ссылку на объект, увидят окончательное (полностью инициализированное) состояние этого поля.
Проблема рваной публикации:

⚠️ Когда объект создается и его ссылка передается (опубликована) другим потокам, инициализация объекта может еще быть не завершена. В этом случае другие потоки могут видеть содержимое объекта в промежуточном состоянии. Это и есть суть "рваной" (racy) публикации.

Поведение volatile поля:

Если volatile поле объекта не было полностью инициализировано на момент, когда ссылка на объект становится видимой другим потокам, то впоследствии эти потоки могут наблюдать значение по умолчанию (например, 0 для примитивных типов).

⚠️ В коде выше делается следующее:

Объект Holder создается, и volatile поле x инициализируется в конструкторе.
Ссылка на объект публикуется в переменной h, которая не является volatile.
Второй поток считывает h и проверяет значение x.
Из-за отсутствия синхронизации (например, volatile для h), есть возможность, что thread2 увидит переменную h как не-null, но значение x еще не инициализированное, в результате чего оно может быть равно 0.

⚠️⚠️ Чтобы избежать подобных проблем:

Используйте final для полей, которые должны быть инициализированы полностью до публикации объекта. Это гарантирует, что другие потоки увидят полностью инициализированный объект.

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

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

🎓 Если вы нашли это обсуждение полезным, ставьте лайк, подписывайтесь и делитесь своими мыслями в комментариях!

#JavaMemoryModel #VolatileFields #FinalFields #Synchronization #java_interview_tasks
🔥10👍41🐳1