Java-параллелизм: много писателей, один читатель

Мне нужно собрать статистику в моем программном обеспечении, и я пытаюсь сделать это быстро и правильно, что нелегко (для меня!)

сначала мой код с двумя классами, 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 минут или что-то разумное.

Написание должно быть как можно быстрее. Чтение должно быть быстрым, но если оно блокируется примерно на 300 мс каждые 5 минут, это нормально.

Я прочитал много документов (Java-параллелизм на практике, эффективный Java и т. Д.), Но у меня есть сильное чувство, что мне нужен ваш совет, чтобы сделать это правильно.

Надеюсь, я изложил свою проблему достаточно четко и кратко, чтобы получить ценную помощь.

РЕДАКТИРОВАТЬ

Спасибо всем за подробные и полезные ответы. Как я и ожидал, есть несколько способов сделать это.

Я проверил большинство ваших предложений (те, которые я понял) и загрузил тестовый проект в код Google для дальнейшего использования (проект 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, поскольку он предлагает хорошую производительность, в то время как его довольно легко понять.

Спасибо за все Ваши ответы! Janning

Ответы на вопрос(9)

Ваш ответ на вопрос