Czym jest warunek wyścigu (Race condition) w programowaniu?

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.

Scroll to Top