2

我定义了以下实例变量:

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

4 回答 4

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

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

于 2019-05-23T19:07:39.647 回答
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 的任何其他排列?

使用 an AtomicIntegerand itsincrementAndGet()方法可以确保每个线程获得不同的值,并且获得的六个值是连续的,没有同步。但这与之后打印结果值的顺序无关。

如果您希望以与获取结果相同的顺序打印结果,那么同步是最简单的方法。在这种情况下,使用 anAtomicInteger不会比使用 plain 获得任何好处int(为此特定目的):

int tradeCounter = 0;

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

或者,不要担心输出的打印顺序。考虑一下:输出顺序是否真的有意义?

于 2019-05-23T19:14:02.663 回答
1

incrementAndGet()按预期顺序递增:1、2、3 等...但system.out不会println()以原子方式 调用incrementAndGet()。所以随机排序是预期的。

我想避免使用同步。

在这种情况下你不能。

于 2019-05-23T19:07:02.447 回答
1

System.out.println(...) 和 tradeCounter.incrementAndGet() 是两个独立的操作,很可能当 thread-i 获得新值时,其他一些线程可以在 thread-i 打印它之前获得并打印它。这里没有办法避免同步(直接或间接)。

于 2019-05-23T19:08:12.033 回答