У вас есть много условий гонки здесь.Следующий результат событий приведет к результату, который вы видите:
Поток A работает до i=198
.Затем происходит переключение контекста, и поток B запускает следующую команду:
System.out.println(name+ ". i = "
+i.getAndIncrement());
внутри цикла while.Поток B создает строку:
"B. I = 198"
Но затем снова происходит переключение контекста на поток A, прежде чем поток B сможет распечатать эту строку.Таким образом, поток A продолжает выполняться, пока не напечатает
A.i = 204
Затем происходит переключение контекста на поток B, и он возобновляет работу с того места, где остановился ранее, при печати строки:
B.i = 198
По сути, у вас есть условие гонки до получения текущего значения i
и его печати.
Другими словами i.getAndIncrement();
является атомарной операцией.Но
System.out.println(name+ ". i = "
+i.getAndIncrement());
НЕ является атомарной операцией.
У вас есть несколько операций.В псевдокоде:
1. tempInt = i.getAndIncrement();
2. tempString1 = name + ". i = ";
3. tempString2 = convertToString(tempInt);
4. tempString3 = tempString1 + tempString2;
5. print tempString3;
Вот почему у вас такой беспорядочный вывод:)
Если вы хотите глубже понять эти понятия, я рекомендую этот онлайн-курс: https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY
Это действительно дешево, и вы можете закончить его за несколько часов.Но это действительно углубляется в те концепции и предостережения с атомарными классами.Это большие затраты времени.
В вашем случае вы действительно хотите использовать синхронизацию вместо AtomicLong, поскольку у вас есть многозадачный критический раздел.
Надеюсь, это поможет.