Является ли куча (Heap) в Java потокобезопасной по умолчанию?

«Является ли куча (Heap) в Java потокобезопасной по умолчанию?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, куча (Heap) в Java не является потокобезопасной. Это общая область памяти, где размещаются объекты, и доступ к ним из нескольких потоков без должной синхронизации приводит к состоянию гонки (race condition) и неопределённому поведению.

Пример проблемы:

public class UnsafeCounter {
    private int count = 0; // Переменная хранится в куче

    public void increment() {
        // Операция count++ НЕ атомарна. Она состоит из:
        // 1. Чтение значения count (read)
        // 2. Увеличение на 1 (increment)
        // 3. Запись нового значения (write)
        count++;
    }
    public int getCount() { return count; }
}
// При одновременном вызове increment() из двух потоков
// конечное значение может быть меньше ожидаемого.

Способы обеспечения потокобезопасности для данных в куче:

  1. Синхронизация (synchronized): Гарантирует атомарность и видимость изменений.
    public synchronized void increment() { count++; }
  2. Ключевое слово volatile: Гарантирует видимость изменений переменной для всех потоков, но не атомарность составных операций.
    private volatile boolean flag; // Подходит для флагов
  3. Атомарные классы (java.util.concurrent.atomic): Обеспечивают атомарность операций над отдельными переменными.
    private AtomicInteger atomicCount = new AtomicInteger(0);
    public void increment() { atomicCount.incrementAndGet(); }
  4. Потокобезопасные коллекции (java.util.concurrent): Например, ConcurrentHashMap, CopyOnWriteArrayList.
  5. Иммутабельные объекты: Объекты, состояние которых нельзя изменить после создания, по своей природе потокобезопасны.

Вывод: Безопасность доступа к данным в куче — ответственность разработчика, достигаемая с помощью механизмов синхронизации.