Warunek wyścigu, znany również jako race condition, występuje w programowaniu wielowątkowym, gdy dwa lub więcej wątków próbują jednocześnie modyfikować zasób współdzielony bez odpowiedniej synchronizacji. W rezultacie, wynik działania programu może zależeć od kolejności, w jakiej wątki wykonują swoje operacje, co prowadzi do nieprzewidywalnych i często błędnych rezultatów.
Przykład warunku wyścigu w Java
Poniżej znajduje się przykład kodu w Javie, który ilustruje problem warunku wyścigu. W tym przykładzie, dwa wątki inkrementują tę samą zmienną counter
. Bez odpowiedniej synchronizacji, wartość counter
po zakończeniu obu wątków może nie być taka, jak oczekiwano.
public class RaceConditionExample {
// Współdzielony licznik
private static int counter = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
incrementCounter(); // Inkrementacja licznika
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
incrementCounter(); // Inkrementacja licznika
}
}
});
t1.start(); // Start pierwszego wątku
t2.start(); // Start drugiego wątku
try {
t1.join(); // Oczekiwanie na zakończenie t1
t2.join(); // Oczekiwanie na zakończenie t2
} catch (InterruptedException e) {
e.printStackTrace();
}
// Wypisanie końcowej wartości licznika
System.out.println("Counter: " + counter);
}
// Metoda do inkrementacji licznika
private static void incrementCounter() {
// Tutaj występuje warunek wyścigu
counter++;
}
}
W powyższym kodzie, metoda incrementCounter
jest wywoływana przez dwa różne wątki (t1
i t2
). Każdy wątek próbuje zwiększyć wartość counter
tysiąc razy. Problem pojawia się, ponieważ operacja inkrementacji (counter++
) nie jest atomowa, co oznacza, że składa się z kilku kroków na poziomie procesora (odczyt wartości, zwiększenie, zapis wartości). Jeśli te kroki przeplatają się między wątkami, wartość końcowa counter
może być niższa niż 2000, ponieważ niektóre inkrementacje mogą nadpisać siebie nawzajem.
Podsumowanie
Warunek wyścigu może prowadzić do subtelnych i trudnych do wykrycia błędów w programach wielowątkowych. Rozwiązaniem jest stosowanie mechanizmów synchronizacji, takich jak blokady (locks), semafory (semaphores) czy inne formy koordynacji wątków, które zapewniają, że krytyczne sekcje kodu są wykonywane w sposób sekwencyjny lub kontrolowany. W przypadku Javy jednym z prostych rozwiązań jest zastosowanie słowa kluczowego synchronized
dla metody incrementCounter
, co zapobiegnie jednoczesnemu dostępowi wielu wątków do sekcji krytycznej.
Jeżeli chcesz przyśpieszyć swoją naukę tworzenia stron chciałbym polecić mój kurs video Java w którym nauczysz się tego języka od podstaw do zaawansowanych jego aspektów.