Проблема, которую вы видите, является классическим случаем состояния гонки.Рассмотрим num += x;
Для вас это выглядит как одна операция, но на самом деле это несколько операций в процессоре.
Проще говоря, это 1. temp1 = num;2. temp2 = x;3. temp3 = temp1 + temp2 4. num = temp3
Это на самом деле происходит в регистрах ЦП, поэтому вы, очевидно, не видите его при написании Java.
Когда у вас естьнесколько потоков, работающих одновременно и выполняющих эти инструкции, могут привести к неожиданному результату.
Например, давайте начнем с x = 1 и num = 2.
Поток A выполняется:
1. temp1a = num;
2. temp2a = x;
3. temp3a = temp1a + temp2a;
4. num = temp3a;
И поток B выполняет
1. temp1b = num;
2. temp2b = x;
3. temp3b = temp1b + temp2b;
4. num = temp3b;
Теперь, если они выполняют эти операции одновременно, вы можете получить следующий порядок:
1. temp1a = num; //2
2. temp2a = x; //1
3. temp3a = temp1a + temp2a; //3
4. temp1b = num; //2
5. temp2b = x; //1
6. temp3b = temp1b + temp2b; //3
7. num = temp3b; //3
8. num = temp3a; //3
Так что, хотя выувеличив num
в два раза, вы получите результат 3 вместо 4. Это условие гонки.Есть много способов избежать этого, и синхронизация - один из них, но есть и другие методы.
Если вы хотите лучше понять это, я очень рекомендую этот онлайн-курс.https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY
Это по-настоящему дешево, и вы можете закончить его за несколько часов, но это объясняет это очень хорошо на примерах, абсолютно с нуля, и это затрагивает очень сложные темы в параллелизме.Это хорошее вложение времени.
В вашем случае просто добавьте синхронизированную, как это:
public synchronized void change(int x) {
num += x;
if (x < 0) {
countNeg++;
} else {
countPos++;
}
System.out.println("number is: " + num + " with operation: " + x);
}
решит проблему, но это не волшебная пуля.Вам следует потратить время на то, чтобы понять, почему проблема решается в этом случае, и не решить ее в другом.
Надеюсь, это поможет.