Я немного удивлен тем, что я получу, если скомпилирую и запусту следующую (ужасную несинхронизированную) программу Java SE.
public class ThreadRace {
// this is the main class.
public static void main(String[] args) {
TestRunnable tr=new TestRunnable(); // tr is a Runnable.
Thread one=new Thread(tr,"thread_one");
Thread two=new Thread(tr,"thread_two");
one.start();
two.start(); // starting two threads both with associated object tr.
}
}
class TestRunnable implements Runnable {
int counter=0; // Both threads can see this counter.
public void run() {
for(int x=0;x<1000;x++) {
counter++;
}
// We can't get here until we've added one to counter 1000 times.
// Can we??
System.out.println("This is thread "+
Thread.currentThread().getName()+" and the counter is "+counter);
}
}
Если я запускаю «java ThreadRace» в командной строке, то вот моя интерпретация
о том, что происходит. Две новые темы созданы и запущены. Темы имеют
тот же Runnable
экземпляр объекта tr
, и поэтому они видят тот же tr.counter
.
Оба новых потока добавляют один к этому счетчику 1000 раз, а затем выводят значение
счетчика.
Если я запускаю это много и много раз, то обычно получаю вывод вида
This is thread thread_one and the counter is 1000
This is thread thread_two and the counter is 2000
и иногда я получаю вывод вида
This is thread thread_one and the counter is 1204
This is thread thread_two and the counter is 2000
Обратите внимание, что в последнем случае произошло то, что thread_one завершил
добавление одного к счетчику 1000 раз, но thread_two начал добавлять
один уже, прежде чем thread_one распечатал значение счетчика.
В частности, этот вывод для меня все еще понятен.
Однако, очень редко я получаю что-то вроде
This is thread thread_one and the counter is 1723
This is thread thread_two and the counter is 1723
Насколько я понимаю, это "не может произойти". Единственный путь System.out.println()
линия
может быть достигнут в любом потоке, если поток закончил считать до 1000.
Так что я не беспокоюсь, если один из потоков сообщает счетчик как некоторые
случайное число от 1000 до 2000, но я не вижу, как оба потока могут
дойти до линии System.out.println()
(подразумевая, что оба цикла завершены,
не так ли?) и счетчик не будет 2000 к тому времени, когда будет напечатано второе утверждение.
То, что происходит, что оба потока как-то пытаются сделать counter++
точно
в то же время, а один перезаписывает другой? То есть нить может быть даже
прерывается даже в середине при выполнении одного оператора ?