Атомная целочисленная печать счетчика в неправильном порядке - PullRequest
2 голосов
/ 23 мая 2019

Я определил следующую переменную экземпляра:

private final AtomicInteger tradeCounter = new AtomicInteger(0);

У меня есть метод onTrade, определенный как ниже и вызываемый 6 потоками:

public void onTrade(Trade trade) {
    System.out.println(tradeCounter.incrementAndGet());
}

Почему вывод:

2 5 4 3 1 6

вместо 1 2 3 4 5 6

Я хочу избежать синхронизации.

Ответы [ 4 ]

2 голосов
/ 23 мая 2019

У меня есть метод onTrade, определенный ниже как вызываемый 6 темы:

public void onTrade(Trade trade) {
    System.out.println(tradeCounter.incrementAndGet());
}

Почему вывод:

2 5 4 3 1 6

Вместо 1 2 3 4 5 6?

Почему не должен быть выводом? Или почему бы не 3 1 4 6 5 2? Или любая другая перестановка 1 2 3 4 5 6?

Использование AtomicInteger и его метода incrementAndGet() гарантирует, что каждый поток получает разные значения и что шесть полученных значений являются последовательными, без синхронизации. Но это не имеет ничего общего с порядком, в котором полученные значения печатаются позже.

Если вы хотите, чтобы результаты печатались в том же порядке, в котором они получены, синхронизация - это самый простой способ. В этом случае использование AtomicInteger ничего не даст вам по сравнению с использованием простого int (для этой конкретной цели):

int tradeCounter = 0;

synchronized public void onTrade(Trade trade) {
    System.out.println(++tradeCounter);
}

В качестве альтернативы, не беспокойтесь о порядке печати вывода. Подумайте: имеет ли смысл какой-либо порядок вывода по какой-либо причине?

2 голосов
/ 23 мая 2019

Вы можете думать о

tradeCounter.incrementAndGet();

и

System.out.println();

как о двух отдельных утверждениях.Итак, здесь

System.out.println(tradeCounter.incrementAndGet());

в основном два утверждения, и эти утверждения вместе не являются атомарными.

Представьте себе такой пример с двумя потоками:

  1. Поток 1 вызываетtradeCounter.incrementAndGet()
  2. активируется поток 2 tradeCounter.incrementAndGet()
  3. поток 2 выводит значение 2
  4. поток 1 выводит значение 1

Все зависит отВ каком порядке потоки будут вызывать в вашем методе инструкции.

1 голос
/ 23 мая 2019

System.out.println (...) и tradeCounter.incrementAndGet () являются двумя отдельными операциями, и наиболее вероятно, когда thread-i получает новое значение, некоторые другие потоки могут получить значение и напечатать его до того, как thread-i напечатает его.Здесь нет способа избежать синхронизации (прямой или косвенной).

1 голос
/ 23 мая 2019

incrementAndGet() приращения в ожидаемом порядке: 1, 2, 3 и т. Д. Но system.out не вызывает println() атомарным образом вдоль incrementAndGet(). Так что ожидается случайный порядок.

Я хочу избежать синхронизации.

Вы не могли бы в этом случае.

...