class UnsafeCounter {
private int count = 0;
// Этот метод не потокобезопасен!
public void increment() {
count++; // ← Три операции: read, modify, write
}
public int getCount() {
return count;
}
}
public class RaceConditionDemo {
public static void main(String[] args) throws InterruptedException {
UnsafeCounter counter = new UnsafeCounter();
// Создаём два потока, каждый увеличивает счётчик 1000 раз
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
thread1.start();
thread2.start();
// Ждём завершения обоих потоков
thread1.join();
thread2.join();
// Ожидаемый результат: 2000
// Реальный результат: почти всегда меньше 2000!
System.out.println("Финальное значение счётчика: " + counter.getCount());
}
} import java.util.concurrent.atomic.AtomicInteger;
class SafeCounter {
// AtomicInteger использует атомарные операции на уровне процессора (CAS)
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // ← Атомарная операция
}
public int getCount() {
return count.get();
}
}
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.");
}
}