原子整数计数器打印顺序错误

时间:2019-05-23 19:00:46

标签: java multithreading atomicinteger

我定义了以下实例变量:

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 个答案:

答案 0 :(得分:2)

您可以想到

tradeCounter.incrementAndGet();

System.out.println();

作为两个单独的语句。 所以在这里

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

基本上有两个语句,而且这些语句不是原子的。

想象一下这样的示例,它有2个线程:

  1. 线程1调用tradeCounter.incrementAndGet()
  2. 线程2调用tradeCounter.incrementAndGet()
  3. 线程2打印出值2
  4. 线程1输出值1

这完全取决于线程在您的方法中调用指令的顺序。

答案 1 :(得分:2)

  

我有一个名为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 :(得分:1)

incrementAndGet()按预期顺序增加:1、2、3等... 但是system.out不会像println()那样以原子方式调用incrementAndGet()。因此,可以预期随机排序。

  

我想避免使用同步。

在这种情况下您无法执行。

答案 3 :(得分:1)

System.out.println(...)和tradeCounter.incrementAndGet()是两个单独的操作,最有可能在线程i获得新值时,某些其他线程可以获取值并在线程i打印之前将其打印。在这里无法避免同步(直接或间接)。