В Java работа с потоками реализуется через классы Thread, Runnable и из пакета java.util.concurrent. Для организации потокобезопасности используются различные механизмы синхронизации:
synchronized) позволяют нескольким потокам обращаться к общим данным без гонок.ReentrantLock, Semaphore, AtomicInteger, ConcurrentHashMap) обеспечивают более гибкие способы синхронизации.Пример синхронизации:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }
Пример с использованием атомарных классов:
import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }
Гарантирует ли ключевое слово volatile потокобезопасность при инкременте счётчика типа int?
Ответ: Нет. volatile обеспечивает только видимость значения между потоками, но не атомарность операций. Инкремент — не атомарная операция (count++ состоит из чтения, увеличения и записи), поэтому возможны потери данных. Для потокобезопасного инкремента нужны синхронизация или классы вроде AtomicInteger.
volatile int count = 0; // count++ не потокобезопасно!
История
В онлайн-магазине бонусный счёт обновлялся через volatile-счётчик. Под нагрузкой тысячи пользователей заказывали товары, и часть бонусов терялась по причине гонки потоков на count++.
История
Сотрудник использовал обычный ArrayList в качестве общего буфера между продюсером и консьюмером в многопоточном приложении, в результате возникали ConcurrentModificationException. Решением стало использование synchronized-блоков или замена на CopyOnWriteArrayList.
История
В обработке платежей разработчик делал операцию "проверить и снять сумму" через два несвязанных метода. В условиях высокой нагрузки это приводило к двойному списанию, пока не внедрили атомарные транзакции и блокировки.