Ответ
Иммутабельные объекты потокобезопасны по своей природе, так как их состояние фиксировано после создания и не может быть изменено. Это устраняет коренные причины проблем многопоточности.
Причины потокобезопасности:
- Отсутствие состояния гонки (Race Condition): Нет операций записи, которые могли бы конфликтовать между потоками.
- Проблема видимости (Memory Visibility) решена: Поскольку все поля объявлены как
final, Java Memory Model гарантирует, что после завершения конструктора эти поля будут корректно видны всем потокам без дополнительной синхронизации. - Отсутствие необходимости в блокировках: Потоки могут только читать данные, что является безопасной операцией.
Пример иммутабельного класса:
public final class ImmutablePerson {
// 1. Класс объявлен как final, чтобы его нельзя было наследовать и переопределить методы.
// 2. Все поля private и final.
private final String name;
private final int age;
private final List<String> hobbies; // Ссылка final, но содержимое списка может быть изменяемым
// 3. Конструктор инициализирует все поля.
public ImmutablePerson(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
// 4. Защитная копия (defensive copy) для изменяемых полей.
this.hobbies = new ArrayList<>(hobbies);
}
// 5. Только геттеры, без сеттеров.
public String getName() { return name; }
public int getAge() { return age; }
// 6. Геттер для изменяемого поля также возвращает защитную копию.
public List<String> getHobbies() { return new ArrayList<>(hobbies); }
}
// Объект этого класса можно свободно передавать между потоками без риска.
Практическое следствие: Такие объекты являются идеальными кандидатами для кэширования, использования в качестве ключей в Map и передачи в конкурентные структуры данных.