java - 如何以线程安全的方式填充字符串映射和另一个映射?

标签 java multithreading concurrency thread-safety guava

我正在使用下面的类来测量我的应用程序指标,其中我递增递减指标。

public class AppMetrics {
  private final AtomicLongMap<String> metricCounter = AtomicLongMap.create();

  private static class Holder {
    private static final AppMetrics INSTANCE = new AppMetrics();
  }

  public static AppMetrics getInstance() {
    return Holder.INSTANCE;
  }

  private AppMetrics() {}     

  public void increment(String name) {
    metricCounter.getAndIncrement(name);
  }

  public AtomicLongMap<String> getMetricCounter() {
    return metricCounter;
  }
}

我正在从多线程代码调用 AppMetrics 类的 increment 方法,以通过传递指标名称来增加指标。

问题陈述:

现在我想为每个 clientId (一个字符串)提供 metricCounter 。这意味着我们还可以多次获取相同的 clientId ,有时它会是一个新的 clientId ,因此我需要以某种方式提取 metricCounter 映射对于该 clientId 并增加该特定 map 上的指标(我不知道如何做到这一点)。

记住它必须是线程安全的并且必须执行原子操作,正确的方法是什么。我正在考虑制作这样的 map :

  private final Map<String, AtomicLongMap<String>> clientIdMetricCounterHolder = Maps.newConcurrentMap();

这是正确的方法吗?如果是,那么我如何通过传递 clientId 作为键来填充此映射,它的值将是每个指标的计数器映射。

我使用的是 Java 7。

最佳答案

如果您使用 map ,则需要同步创建新的 AtomicLongMap 实例。我建议使用 LoadingCache 代替。您最终可能不会使用任何实际的“缓存”功能,但“加载”功能非常有用,因为它将为您同步创建 AtomicLongMap 实例。例如:

LoadingCache<String, AtomicLongMap<String>> clientIdMetricCounterCache =
        CacheBuilder.newBuilder().build(new CacheLoader<String, AtomicLongMap<String>>() {
            @Override
            public AtomicLongMap<String> load(String key) throws Exception {
                return AtomicLongMap.create();
            }
        });

现在您可以安全地开始更新任何客户端的指标计数,而不必担心客户端是否是新的。例如

clientIdMetricCounterCache.get(clientId).incrementAndGet(metricName);

关于java - 如何以线程安全的方式填充字符串映射和另一个映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40983236/

相关文章:

java - 适合新手的并发编程

java - 如果这不是线程安全的,我可以通过哪些方式使其成为线程安全的?

java - 从 getName() 的结果中刷新选项卡名称

java - 我无法签署我的代码。对最终用户会产生什么影响?

c++ - 重新启动后,线程无法在while循环中再次运行

c++ - 没有内核调用的 pthread 信号

java - 正则表达式来匹配此模式

java - Lucene搜寻器(需要建立Lucene索引)

c++ - 确保当前线程持有 C++11 互斥锁

java - 廉价读写锁中的冗余 volatile ?