gpt4 book ai didi

java concurrency : many writers, 一个读者

转载 作者:太空狗 更新时间:2023-10-29 22:37:43 25 4
gpt4 key购买 nike

我需要在我的软件中收集一些统计数据,我正在努力使其快速且正确,这并不容易(对我来说!)

到目前为止,我的代码首先包含两个类,一个 StatsService 和一个 StatsHarvester

public class StatsService
{
private Map<String, Long> stats = new HashMap<String, Long>(1000);

public void notify ( String key )
{
Long value = 1l;
synchronized (stats)
{
if (stats.containsKey(key))
{
value = stats.get(key) + 1;
}
stats.put(key, value);
}
}

public Map<String, Long> getStats ( )
{
Map<String, Long> copy;
synchronized (stats)
{
copy = new HashMap<String, Long>(stats);
stats.clear();
}
return copy;
}
}

这是我的第二堂课,一个收割机,它不时收集统计数据并将它们写入数据库。

public class StatsHarvester implements Runnable
{
private StatsService statsService;
private Thread t;

public void init ( )
{
t = new Thread(this);
t.start();
}

public synchronized void run ( )
{
while (true)
{
try
{
wait(5 * 60 * 1000); // 5 minutes
collectAndSave();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}

private void collectAndSave ( )
{
Map<String, Long> stats = statsService.getStats();
// do something like:
// saveRecords(stats);
}
}

在运行时,它将有大约 30 个并发运行的线程,每个线程调用 notify(key) 大约 100 次。只有一个 StatsHarvester 正在调用 statsService.getStats()

所以我有很多作家,只有一个读者。拥有准确的统计数据会很好,但我不在乎是否在高并发时丢失了一些记录。

读取器应每 5 分钟或任何合理的时间运行一次。

写作应该尽可能快。阅读应该很快,但如果它每 5 分钟锁定大约 300 毫秒,就可以了。

我已经阅读了很多文档(Java 并发实践、effective java 等),但我有一种强烈的感觉,我需要您的建议才能正确完成。

我希望我的问题表述清楚且简短,以获得有值(value)的帮助。


编辑

感谢大家提供详细而有用的答案。正如我所料,有不止一种方法可以做到这一点。

我测试了你的大部分建议(我理解的那些)并上传了一个测试项目到谷歌代码以供进一步引用(maven 项目)

http://code.google.com/p/javastats/

我测试了 StatsService 的不同实现

  • HashMapStatsService (HMSS)
  • ConcurrentHashMapStatsService (CHMSS)
  • LinkedQueueStatsService (LQSS)
  • GoogleStatsService (GSS)
  • ExecutorConcurrentHashMapStatsService (ECHMSS)
  • ExecutorHashMapStatsService (EHMSS)

我用 x 个线程对它们进行了测试,每次调用通知 y 次,结果以毫秒为单位

         10,100   10,1000  10,5000  50,100   50,1000  50,5000  100,100  100,1000 100,5000 
GSS 1 5 17 7 21 117 7 37 254 Summe: 466
ECHMSS 1 6 21 5 32 132 8 54 249 Summe: 508
HMSS 1 8 45 8 52 233 11 103 449 Summe: 910
EHMSS 1 5 24 7 31 113 8 67 235 Summe: 491
CHMSS 1 2 9 3 11 40 7 26 72 Summe: 171
LQSS 0 3 11 3 16 56 6 27 144 Summe: 266

此时我想我会使用 ConcurrentHashMap,因为它提供了很好的性能,而且它很容易理解。

感谢您的参与!詹宁

最佳答案

正如 jack 所说,您可以使用 java.util.concurrent 库,其中包括一个 ConcurrentHashMap 和 AtomicLong。如果没有其他情况,您可以将 AtomicLong 放入,您可以增加该值。由于 AtomicLong 是线程安全的,您将能够增加变量而不必担心并发问题。

public void notify(String key) {
AtomicLong value = stats.get(key);
if (value == null) {
value = stats.putIfAbsent(key, new AtomicLong(1));
}
if (value != null) {
value.incrementAndGet();
}
}

这应该既快又线程安全

编辑:轻微重构,因此最多只有两次查找。

关于java concurrency : many writers, 一个读者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2539654/

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