#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);
}
}
(похожая задача была тут - 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);
}
}
Telegram
Java Interview Tasks
#concurrency #java
class A {
int a;
int b;
void m1() {
a++;
b++;
}
void m2() {
System.out.println(b);
System.out.println(a);
}…
class A {
int a;
int b;
void m1() {
a++;
b++;
}
void m2() {
System.out.println(b);
System.out.println(a);
}…
Какие значения может напечатать код (thread1 и thread2 запускаются одновременно в разных потоках)?
#jmm #concurrency #java #java_interview_tasks
#jmm #concurrency #java #java_interview_tasks
👍11
Ответ на вопрос VolatileVsFinal (https://t.me/java_interview_tasks/140) :
Тут речь идет об одном из самых интересных разрешенных сценариев JMM. Это тот факт, что volatile поле не имеет final семантики.
Это означает, что если мы публикуем ссылку объекта под гонкой, то мы можем увидеть дефолтное значение для volatile поля
Поэтому в данном случае 0 вполне можно получить.
Этот эффект можно увидеть на некоторых платформах, например AArch64:
Тут речь идет об одном из самых интересных разрешенных сценариев 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%
Telegram
Java Interview Tasks
Какие значения может напечатать код (thread1 и thread2 запускаются одновременно в разных потоках)?
#jmm #concurrency #java #java_interview_tasks
#jmm #concurrency #java #java_interview_tasks
👍16🔥7🤯3❤1
Forwarded from xpinjection
Если вы разрабатываете на Java, то видео доклада в этом посте точно расширит ваш кругозор. Java выбирают даже не за язык, а скорее за огромную экосистему, в которой разработчики могут найти готовые решения для практически любых задач. Эту экосистему важно знать. В докладе рассматривается большой список библиотек из мира Java для решения конкретных прикладных задач.
Если вы не разрабатываете на Java, но знаете Java разработчиков, поделитесь с ними этим видео. Они точно скажут вам спасибо! :)
#Java
https://youtube.com/watch?v=ABm0KhsZJ0c&feature=share9
Если вы не разрабатываете на Java, но знаете Java разработчиков, поделитесь с ними этим видео. Они точно скажут вам спасибо! :)
#Java
https://youtube.com/watch?v=ABm0KhsZJ0c&feature=share9
YouTube
Java's Hidden Gems: Tools and Libraries by Johan Janssen
For more info on the next Devoxx UK event 👉 www.devoxx.co.uk
This session is a whirlwind tour of many lesser known, but very interesting, Java tools and libraries. We'll have a sneak peak at dozens of tools to improve security, builds, architecture, tests…
This session is a whirlwind tour of many lesser known, but very interesting, Java tools and libraries. We'll have a sneak peak at dozens of tools to improve security, builds, architecture, tests…
🔥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 #разработка
Разберемся, как 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 #разработка
Telegram
Java Interview Tasks
Что напечатает код? (Супермаловероятными событиями тут пренебрегаем)
👍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 #многопоточность #исключения #программирование #лучшиепрактики
Привет, друзья! Сегодня обсудим скрытую проблему с логированием исключений, которая часто возникает в многопоточной среде.
На первый взгляд все кажется довольно обычным: мы отправляем задачу на выполнение, которая вызывает метод 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 #многопоточность #исключения #программирование #лучшиепрактики
🔥14❤4👍4🙏1
🔍 Ответ на вопрос про volatile и массивы в Java:
📌 Многие разработчики могут ошибочно полагать, что при объявлении массива volatile все его элементы также будут обладать свойствами volatile. Однако это не так!
Пример выше как раз демонстрирует эту особенность.
🔎 Объяснение:
volatile int[] arr делает переменную arr ссылкой volatile. Это означает, что любые изменения ссылки на массив будут видны другим потокам.
Однако элементы массива не наследуют volatile-свойство. Таким образом, arr[0] и arr[1] не имеют гарантий видимости друг для друга.
➖➖➖➖➖
Ставьте лайк , если нашли это полезным и задавайте свои вопросы и комментарии ниже для получения дополнительных знаний! 🚀
#java #многопоточность #volatile #программирование
📌 Многие разработчики могут ошибочно полагать, что при объявлении массива volatile все его элементы также будут обладать свойствами volatile. Однако это не так!
Пример выше как раз демонстрирует эту особенность.
🔎 Объяснение:
volatile int[] arr делает переменную arr ссылкой volatile. Это означает, что любые изменения ссылки на массив будут видны другим потокам.
Однако элементы массива не наследуют volatile-свойство. Таким образом, arr[0] и arr[1] не имеют гарантий видимости друг для друга.
➖➖➖➖➖
Ставьте лайк , если нашли это полезным и задавайте свои вопросы и комментарии ниже для получения дополнительных знаний! 🚀
#java #многопоточность #volatile #программирование
Telegram
Java Interview Tasks
Какие значения могут напечататься? (thread1 и thread2 запускаются одновременно в разных потоках)
🔥9👍4❤3👎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
🚀🚀🚀Когда вы вызываете метод в 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🔥5❤3
🔍 Ответ на задачу про распределение монет по кошелькам
⚠️Это задача на метод 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
⚠️Это задача на метод 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🔥3❤2👎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
В 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👍6⚡1❤1👏1🐳1
🔍 Ответ на задачу о ConcurrentHashMap и атомарности
Одно из часто обсуждаемых свойств ConcurrentHashMap — это ее потокобезопасность в отношении методов put и get. ConcurrentHashMap гарантирует атомарность операций put и get, что значит, что каждое из этих действий выполняется полностью или не выполняется вовсе, и они могут безопасно выполняться одновременно из разных потоков.
⚡️Однако важно помнить, что эта гарантия распространяется только на сами операции put и get, но не на атомарность действий по отношению к вложенным объектам. В нашем случае, если мы извлекаем список из мапы и затем изменяем его, эти изменения не защищены от состояния гонки. Как было показано в предыдущей задаче, два потока могут создать и модифицировать один и тот же список, приводя к непредсказуемым результатам.
⚡️⚡️Поэтому при работе с ConcurrentHashMap, когда объекты, хранящиеся в мапе, также должны быть потокобезопасными, следует дополнительно обеспечивать синхронизацию либо использовать другие потокобезопасные структуры данных.
👉 Чтобы решить проблему, можно воспользоваться несколькими подходами. Вот некоторые из них:
/*
Solves the race with putIfAbsent
*/
/*
Solves the race with computeIfAbsent.
*/
🎓 Понравилась тема про потокобезопасность в Java? Ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
#ConcurrentHashMap #Java #Concurrency #Atomicity #java_interview_tasks
Одно из часто обсуждаемых свойств 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🔥4❤2👏1
🔍 Ответ на задачу про checkThenReact и состояние гонки:
В этом примере метода checkThenReact() описывается ситуация типичной проблемы конкурентного программирования, известной как "состояние гонки". Суть проблемы заключается в том, что несколько потоков (в данном случае actor1() и actor2()) могут одновременно проверить и изменить общее состояние, здесь представляемое переменной flag.
Возможные решения для устранения состояния гонки:
Синхронизация:
Заключите операцию проверки и изменения flag в блок синхронизации:
Использование AtomicBoolean:
Замена boolean на AtomicBoolean и использование атомарных операций. Например:
Эти подходы помогут устранить логическую проблему и гарантировать, что только один поток сможет изменить состояние flag в одно и то же время.
🎓Если вам интересны темы конкурентности и потокобезопасности, ставьте лайк, подписывайтесь и оставляйте комментарии с вашими вопросами и переживаниями!
#Concurrency #RaceCondition #Synchronization #AtomicOperations #java_interview_tasks
В этом примере метода 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
Telegram
Java Interview Tasks
Что может напечатать код? (методы actor1 и actor2 запускаются параллельно в разных тредах)
👍16🔥3❤1👌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
Данная задача подчеркивает одно из потенциально неожиданных поведений модели памяти 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👍4❤1🐳1