【问题标题】:Using AtomicInteger as a static shared counter使用 AtomicInteger 作为静态共享计数器
【发布时间】:2012-04-09 18:34:05
【问题描述】:

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

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

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

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

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 也是如此。

我感觉我遗漏了一些非常明显的东西。

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

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

    这是在这些情况下经常发生的竞争条件。尽管AtomicInteger 计数器正在正确递增,但没有什么可以阻止Thread 2 被换出增量发生并且之前println 被调用。

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

    如果您想打印“100% 的时间顺序计数器”,您将不得不在增量 println 调用周围同步锁定。当然,如果你这样做了,那么 AtomicInteger 就被浪费了。

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

    如果您编辑您的问题来解释为什么您需要输出是连续的,也许有更好的解决方案没有这种竞争条件。

    【讨论】:

    • 没有什么特别的原因我想要顺序输出,除了我只是为了学习目的而弄乱不同的同步场景。我想我现在也终于理解了同步块。非常感谢。
    • 我想@jskiles1 一样多。竞争条件可能很棘手和令人困惑。那里有很多很好的教程。这是一个看起来不错的。祝你好运。 vogella.de/articles/JavaConcurrency/article.html
    【解决方案2】:

    您需要为此同步整个构造:

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

    不过,在这种情况下,您不必使用 AtomicInteger。普通的int 可以工作(counter++)。

    【讨论】:

      【解决方案3】:

      要按顺序打印,incAndGet 和 println 必须都在临界区,一段代码只有一个线程可以进入,其他线程被阻塞。可以通过二进制信号量实现,例如 java synchronized

      你可以把事情放在头上,让一个线程增加一个计数器并打印它。其他线程可能在“临界区”中只占用一个接一个的计数器。这样会更有效率,因为关键区域应该保持较小并且最好不要 I/O。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-01
        • 2010-09-06
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-03
        • 2011-05-26
        相关资源
        最近更新 更多