Пример гонки данных Java с использованием счетчика

#java #multithreading #race-condition

#java #многопоточность #условие гонки

Вопрос:

Вот несколько простых примеров метода, который не использует синхронизацию и вызывает гонку данных и его «улучшенную» версию без этой проблемы

 class Counter {
    public static long count = 0;
}

class UseCounter implements Runnable {    
    public static void increment() {
        Counter.count  ;
        System.out.print(Counter.count   " ");
    }    
    public void run() {
        increment();
        increment();
        increment();
    }    
}

class SynchronizedUseCounter implements Runnable {    
    public static synchronized void increment() {
        Counter.count  ;
        System.out.print(Counter.count   " ");
    }    
    public void run() {
        increment();
        increment();
        increment();
    }
}

public class DataRaces {
    public static void main(String[] args) {
        UseCounter c = new UseCounter();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        Thread t3 = new Thread(c);
        t1.start();
        t2.start();
        t3.start();

        Counter.count = 0;

        SynchronizedUseCounter sc = new SynchronizedUseCounter();
        Thread t4 = new Thread(sc);
        Thread t5 = new Thread(sc);
        Thread t6 = new Thread(sc);
        t4.start();
        t5.start();
        t6.start();
    }
}
 

Он печатает что-то вроде этого:

1 2 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Первые 9 цифр — гонка данных, следующие 9 цифр — гонки данных нет, почти как ожидалось, но как насчет этой строки перед инициализацией и запуском потоков с помощью синхронизированных методов?

 Counter.count = 0;
 

Почему это не сработало?

Ответ №1:

Вы не дождались завершения первых потоков перед сбросом счетчика, а поскольку для запуска потоков требуется время, весьма вероятно, что count = 0; это произойдет задолго до запуска любого потока.

Ответ №2:

Это не работает, потому что ранее запущенные три потока все еще выполняются и увеличивают переменную. Вы должны присоединиться к потокам, чтобы дождаться их завершения, прежде чем продолжить со вторым тестовым примером.

 t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();