使用AtomicInteger作为静态共享计数器 [英] Using AtomicInteger as a static shared counter

查看:407
本文介绍了使用AtomicInteger作为静态共享计数器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了通过Java了解同步,我只是搞乱一些简单的事情,比如创建一个在线程之间共享的计数器。

In an effort to learn about synchronization via Java, I'm just messing around with some simple things like creating a counter shared between threads.

我遇到的问题是我无法弄清楚如何在100%的时间内依次打印计数器。

The problem I've run into is that I can't figure out how to print the counter sequentially 100% of the time.

int counterValue = this.counter.incrementAndGet();
System.out.println(this.threadName + ": " + counterValue);

上面增加 AtomicInteger计数器,得到新值,并将其打印到由负责该更新的线程名称标识的控制台。当出现 incrementAndGet()方法导致JVM在打印当前线程的更新值之前上下文切换到另一个线程以进行更新时,会出现问题。这意味着在线程返回执行状态之前,该值会增加但不会打印。查看此示例输出时很明显:

The above increments the AtomicInteger counter, gets the new value, and prints it to the console identified by the thread name that is responsible for that update. The problem occurs when it appears that the incrementAndGet() method is causing the JVM to context switch to another thread for its updates before printing the current thread's updated value. This means that the value gets incremented but not printed until the thread returns to the executing state. This is obvious when looking at this example output:

Thread 3: 4034
Thread 3: 4035
Thread 3: 4036
Thread 1: 3944
Thread 1: 4037
Thread 1: 4039
Thread 1: 4040
Thread 2: 3863
Thread 1: 4041
Thread 1: 4043

您可以看到执行返回到线程1时,它打印其值并继续更新。线程2也是如此。

You can see that when execution returns to Thread 1, it prints its value and continues updating. The same is evident with Thread 2.

我感觉我错过了一些非常明显的东西。

I have a feeling that I'm missing something very obvious.

推荐答案


在打印当前线程的更新值之前,似乎incrementAndGet()方法导致JVM上下文切换到另一个线程以进行更新时出现问题

The problem occurs when it appears that the incrementAndGet() method is causing the JVM to context switch to another thread for its updates before printing the current thread's updated value

这是一种在这些情况下经常发生的竞争条件。虽然 AtomicInteger 计数器正在递增,但没有什么可以阻止线程2 被换出之后增加了 之前

This is a race condition that often can happen in these situations. Although the AtomicInteger counters are being incremented properly, there is nothing to stop Thread 2 from being swapped out after the increment happens and before the println is called.

int counterValue = this.counter.incrementAndGet();
// there is nothing stopping a context switch here
System.out.println(this.threadName + ": " + counterValue);

如果你想在100%的时间内依次打印计数器,你将不得不同步锁定增量 println 调用。当然,如果你这样做,那么 AtomicInteger 就会被浪费。

If you want to print the "counter sequentially 100% of the time" you are going to have to synchronize on a lock around both the increment and the println call. Of course if you do that then the AtomicInteger is wasted.

synchronized (counter) {
    System.out.println(this.threadName + ": " + counter.incrementAndGet());
}

如果你编辑你的问题来解释为什么你需要输出是顺序的可能有一个更好的解决方案,没有这种竞争条件。

If you edit your question to explain why you need the output to be sequential maybe there is a better solution that doesn't have this race condition.

这篇关于使用AtomicInteger作为静态共享计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆