simultaneidade java: muitos escritores, um leitor

Preciso reunir algumas estatísticas no meu software e estou tentando torná-lo rápido e correto, o que não é fácil (para mim!)

primeiro meu código até agora com duas classes, um StatsService e um 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;
}
}

esta é minha segunda classe, uma colheitadeira que coleta as estatísticas de tempos em tempos e as grava em um banco de dados.

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);
}
}

Em tempo de execução, ele terá cerca de 30 threads simultâneos em execução cada chamadanotify(key)&nbsp;cerca de 100 vezes. Apenas um StatsHarvester está chamandostatsService.getStats()

Então, eu tenho muitos escritores e apenas um leitor. seria bom ter estatísticas precisas, mas não me importo se alguns registros forem perdidos em alta simultaneidade.

O leitor deve executar a cada 5 minutos ou o que for razoável.

Escrever deve ser o mais rápido possível. A leitura deve ser rápida, mas se travar por cerca de 300 ms a cada 5 minutos, tudo bem.

Eu já li muitos documentos (concorrência Java na prática, java eficaz e assim por diante), mas tenho a forte sensação de que preciso do seu conselho para fazer a coisa certa.

Espero ter declarado meu problema claro e curto o suficiente para obter ajuda valiosa.

EDITAR

Obrigado a todos por suas respostas detalhadas e úteis. Como eu esperava, há mais de uma maneira de fazê-lo.

Testei a maioria das suas propostas (aquelas que eu entendi) e enviei um projeto de teste para o google code para obter mais referências (projeto maven)

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

Testei diferentes implementações do meu StatsService

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

e eu os testei comx&nbsp;número de threads que cada chamada notificay&nbsp;vezes, os resultados estão em ms

         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

Neste momento, acho que vou usar o ConcurrentHashMap, pois oferece um bom desempenho e é muito fácil de entender.

Obrigado por toda a sua contribuição! Janning