首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于单写入线程的AtomicXXX lazySet

用于单写入线程的AtomicXXX lazySet
EN

Stack Overflow用户
提问于 2014-08-19 16:57:00
回答 4查看 155关注 0票数 0

我有一个只有一个编写线程的应用程序,它可以做一些事情并更新一些度量指标,例如计数器等。这个应用程序有许多其他线程,它们读取统计数据并使用它们进行操作。这些指标必须是最新的,这并不重要,但是编写线程需要尽可能少的时间被阻塞。我想知道下列哪一项更适合我的需要:

选项1-有一个只有写入器才能更新的非原子字段和一个使用AtomicXXX设置的lazySet字段

代码语言:javascript
复制
class Stats1
{
  private final AtomicLong someCounterAtomic = new AtomicLong(0);
  private long someCounter = 0;

  // writer thread updates the stats using this
  public void incrementCounter(long counterIncrement)
  {
    someCounter += counterIncrement;
    someCounterAtomic.lazySet(someCounter);
  }

  // reader threads call this
  public long getCounterValue()
  {
    return someCounterAtomic.get();
  }
}

选项2-只有一个通过AtomicXXX更新的addAndGet字段

代码语言:javascript
复制
class Stats2
{
  private final AtomicLong someCounter = new AtomicLong(0);

  // writer thread updates the stats using this
  public void incrementCounter(long counterIncrement)
  {
    someCounter.addAndGet(counterIncrement);
  }

  // reader threads call this
  public long getCounterValue()
  {
    return someCounter.get();
  }
}

还是我还是做点别的更好?

提前谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-08-19 18:08:41

如果有些最近的统计是好的,我不会同步任何东西。我会让作者的线程定期拍摄快照,并通过原子引用定期(或在统计数据发生足够大的变化之后)发布。

代码语言:javascript
复制
public class Stats {
     // the currently available stat instance
     public static AtomicReference<Stats> CURRENT_STATS = 
         new AtomicReference<>(new Stats());

     private final int whatever1;
     private final int whatever2;

     private Stats() {
         this(0, 0);
     }

     public Stats(int whatever1, int whatever2) {
         this.whatever1 = whatever1;
         ...
     }

     public int getWhatever1() {
         return whatever1;
     }

     public int getWhatever2() {
         return whatever2;
     }

}

作者只是在认为合适时创建一个新的Stats实例,并设置CURRENT_STATS引用。读者只需在需要统计数据时阅读引用,并将引用保持到当前处理传递完成为止(避免在处理时更改统计数据)。

这需要最低限度的同步,当对统计数据的最新需求比较宽松时(例如,向用户显示吞吐量等),这是合适的。不管Stats公开了多少变量,一个原子引用都可以控制它们。

票数 1
EN

Stack Overflow用户

发布于 2014-08-19 17:09:55

只需使用addAndGet。它很简单,可以立即识别,而且很可能足够快。

如果只有一个线程更新计数器,那么addAndGet是没有争议的,并且将与您的Stats1代码一样快。如果有多个线程在更新,那么Stats1就是完全错误的。无论哪种方式,您都不应该使代码复杂化,除非您有基准测试/分析数据,这表明这对您的应用程序的总体运行时间来说是一个很大的成本。

票数 3
EN

Stack Overflow用户

发布于 2014-08-19 18:40:13

如果您使用的是Java 8,则应该考虑java.util.concurrent.atomic中的java.util.concurrent.atomic类:

当多个线程更新一个用于收集统计信息,而不是用于细粒度同步控制的公共和时,这个类通常比AtomicLong更好。在低更新争用条件下,两类具有相似的特性。但是在竞争激烈的情况下,这类的预期吞吐量要高得多,而牺牲了更高的空间消耗。

请注意,如果您遵循“永不同步”这一公认的答案中的建议,那么统计数据可能永远不会更新(取决于您的程序中还发生了什么,运行的是哪个体系结构,哪个Java等等)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25388989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档