gpt4 book ai didi

java - 并发频率计数器-并发问题

转载 作者:行者123 更新时间:2023-12-02 06:13:57 25 4
gpt4 key购买 nike

我想用 Java 创建一个并发频率计数器类。

一旦处理了请求(通过 processRequest 方法),代码就会检查请求的类型(整数)并计算给定时间内已处理的请求数量(按请求类型分组)。 processRequest方法会被多个线程同时调用。

还有另外两种方法:

  • clearMap():每3小时由一个线程调用,清除整个 map 。
  • getMap():Web 服务可以随时调用它,并返回频率图当前状态的不可变副本。

请参阅下面我实现该计划的初步计划。

public class FrequencyCounter {

private final ConcurrentHashMap<Integer,Long> frequencenyMap = new ConcurrentHashMap<>();

public void processRequest(Request request){
frequencenyMap.merge(request.type, 0L, (v, d) -> v+1);
}

public void clearMap(){
frequencenyMap.clear();
}

public Map<Integer,Long> getMap(){
return ImmutableMap.copyOf(frequencenyMap);
}
}

我检查了ConcurrentHashMap的文档,它告诉我们merge方法是原子执行的。

因此,一旦clear()方法开始清除映射的哈希桶(根据哈希桶锁定),当另一个线程在获取频率映射的值和增加其值之间时,它就不能被调用processRequest 方法,因为 merge 方法是原子执行的。

我说得对吗?我上面的方案看起来还可以吗?

谢谢你的建议。

最佳答案

首先,替换Long AtomicLong .

第二,使用 computeIfAbsent .

 private final Map<Integer, AtomicLong> frequencyMap = new ConcurrentHashMap<>();

public void processRequest(Request request){
frequencyMap.computeIfAbsent(request.type, k -> new AtomicLong())
.incrementAndGet();
}

我相信这是一个更好的解决方案有几个原因:

  1. 问题中的代码使用盒装对象,即 (v, d) -> v+1真是(Long v, Long d) -> Long.valueOf(v.longValue() + 1) .

    该代码会生成额外的垃圾,可以通过使用 AtomicLong 来避免。 .

    这里的代码只为每个键分配一个对象,并且不需要任何额外的分配来增加计数器,例如即使计数器达到数百万,它仍然只是一个对象。

  2. 拆箱、加 1、装箱操作可能会比严格编码的 incrementAndGet() 花费稍长的时间。操作,增加了碰撞的可能性,需要在 merge 中重试方法。

  3. 代码“纯度”。使用一种接受“值”的方法,然后完全忽略它,对我来说似乎是错误的。这是不必要的代码噪音。

这些当然是我的意见。您可以做出自己的决定,但我认为这段代码阐明了目的,即增加 long计数器,以完全线程安全的方式。

关于java - 并发频率计数器-并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55883900/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com