12 Что такое race condition? Что такое deadLock? Что такое live-lock?
В многопоточном программировании важно понимать различные проблемы, которые могут возникнуть при взаимодействии потоков. Три из таких проблем — это race condition, deadlock и live-lock. Давайте рассмотрим каждую из них подробнее.
Race Condition
Race condition (состояние гонки) возникает, когда два или более потоков одновременно пытаются изменить одно и то же состояние или ресурс, и результат выполнения зависит от порядка выполнения потоков. Это может привести к непредсказуемым и неправильным результатам.
Пример:
Предположим, у нас есть общий счетчик, который увеличивается двумя потоками:
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class RaceConditionExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
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();
System.out.println("Final count: " + counter.getCount()); // Ожидается 2000, но может быть меньше
}
}
В этом примере, если два потока одновременно увеличивают счетчик, результат может быть непредсказуемым из-за состояния гонки.
Deadlock
Deadlock (взаимная блокировка) — это ситуация, когда два или более потоков блокируют друг друга, ожидая освобождения ресурсов, которые они уже захватили. В результате ни один из потоков не может продолжить выполнение.
Пример:
public class DeadlockExample {
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("Thread 1: Holding lock 1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (lock2) {
System.out.println("Thread 1: Acquired lock 2!");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (lock1) {
System.out.println("Thread 2: Acquired lock 1!");
}
}
});
thread1.start();
thread2.start();
}
}
В этом примере, если Thread 1
захватывает lock1
и ожидает lock2
, а Thread 2
захватывает lock2
и ожидает lock1
, оба потока окажутся в состоянии блокировки.
Live-lock
Live-lock — это ситуация, когда потоки продолжают изменять свое состояние, но не могут завершить выполнение, потому что они постоянно реагируют на действия друг друга. В отличие от deadlock, потоки не блокируются, но не могут продвинуться вперед.
Пример:
public class LiveLockExample {
private static class Person {
private String name;
private boolean wantsToTalk;
public Person(String name) {
this.name = name;
this.wantsToTalk = true;
}
public void talkTo(Person other) {
while (this.wantsToTalk) {
System.out.println(this.name + " wants to talk to " + other.name);
this.wantsToTalk = false; // Отказ от разговора
other.wantsToTalk = true; // Другой хочет поговорить
}
}
}
public static void main(String[] args) {
Person alice = new Person("Alice");
Person bob = new Person("Bob");
Thread thread1 = new Thread(() -> alice.talkTo(bob));
Thread thread2 = new Thread(() -> bob.talkTo(alice));
thread1.start();
thread2.start();
}
}
В этом примере, оба человека хотят поговорить, но они постоянно отказываются от разговора, что приводит к ситуации live-lock.
Заключение
- Race Condition: Проблема, возникающая из-за однов