#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();