Почему объекты класса String в Java являются потокобезопасными?

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

Ответ

Класс String является потокобезопасным по своей природе, потому что он иммутабелен (неизменяем).

Ключевые характеристики иммутабельности String:

  1. Класс объявлен как final — от него нельзя наследоваться и изменить поведение.
  2. Данные хранятся в приватном final массиве символов (private final char value[] или byte[] в новых версиях).
  3. Не существует публичных методов, которые изменяют внутреннее состояние строки после ее создания.

Как это обеспечивает потокобезопасность:

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

Пример «изменения» строки:

String original = "Hello";
String modified = original.concat(", World!");

System.out.println(original); // Вывод: "Hello" (не изменилась!)
System.out.println(modified); // Вывод: "Hello, World!" (новый объект)
// original == modified? false. Это разные объекты в памяти.

Методы concat(), substring(), toUpperCase() и другие всегда возвращают новый объект String, а не модифицируют исходный.

Вывод: Иммутабельность делает String по умолчанию потокобезопасным, что критически важно, так как строки широко используются в многопоточных средах (например, как ключи в ConcurrentHashMap).