List<String> unsafeList = new ArrayList<>();
// Если несколько потоков одновременно вызывают этот метод, возникнет ConcurrentModificationException
// или данные могут быть повреждены
public void addItem(String item) {
unsafeList.add(item); // ← Не потокобезопасная операция
} // Создание CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// Поток 1: добавление элементов
list.add("Элемент 1"); // ← Создаётся новый массив с этим элементом
list.add("Элемент 2"); // ← Создаётся ещё один новый массив с обоими элементами
// Поток 2: чтение элементов (не блокируется)
for (String item : list) { // ← Работает с копией массива
System.out.println(item);
}
// Список слушателей событий в GUI-приложении
CopyOnWriteArrayList<EventListener> listeners = new CopyOnWriteArrayList<>();
// Добавление слушателей (редкая операция)
public void addListener(EventListener listener) {
listeners.add(listener); // ← Создаётся новая копия массива
}
// Уведомление слушателей (частая операция)
public void notifyListeners(Event event) {
for (EventListener listener : listeners) { // ← Безопасная итерация
listener.onEvent(event); // ← Не бросает ConcurrentModificationException
}
} public class DeadlockDemo {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Поток 1: Захватил lock1...");
try { Thread.sleep(50); } catch (InterruptedException e) {}
System.out.println("Поток 1: Ожидаю lock2...");
synchronized (lock2) { // ← Блокировка! Ждёт lock2, который удерживает поток 2
System.out.println("Поток 1: Захватил lock1 и lock2.");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Поток 2: Захватил lock2...");
try { Thread.sleep(50); } catch (InterruptedException e) {}
System.out.println("Поток 2: Ожидаю lock1...");
synchronized (lock1) { // ← Блокировка! Ждёт lock1, который удерживает поток 1
System.out.println("Поток 2: Захватил lock2 и lock1.");
}
}
});
thread1.start();
thread2.start();
}
} ┌───────────────────┐ ┌───────────────────┐
│ Поток 1 │ │ Поток 2 │
└─────────┬─────────┘ └─────────┬─────────┘
│ │
Захватил lock1 Захватил lock2
│ │
▼ ▼
Ожидает lock2 ◄──────────────► Ожидает lock1
// Исправленная версия: оба потока захватывают замки в одном порядке
synchronized (lock1) {
System.out.println("Поток 1: Захватил lock1...");
synchronized (lock2) {
System.out.println("Поток 1: Захватил lock1 и lock2.");
}
} // Поток 2 теперь тоже сначала захватывает lock1
synchronized (lock1) {
System.out.println("Поток 2: Захватил lock1...");
synchronized (lock2) {
System.out.println("Поток 2: Захватил lock1 и lock2.");
}
}