Collections.synchronizedMap VS ConcurrentHashMap

Antigamente até a verão 1.4.* do java quando precisávamos de uma Map sincronizado, normalmente faríamos isso:


Map map = Collections.synchronizedMap(new HashMap());


Qual o problema de se fazer isso?

Neste caso todos os métodos do Map serão Syncronized, mas sem nehuma ligação entre si. Então nesse caso é melhor fazer blocos sincronizados e você mesmo controlar a sincronização. Atualmente temos o Java 6.0, já mas a partir do java 5.0 entrou a class:




java.util.concurrent.ConcurrentHashMap


Que nada mais é que um Map com suporte a acesso concorrente. Esse package novo java.util.concurrent é só para acesso concorrente.

Vejá o Benchmark

GlobalTimes.java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GlobalTimes {

List tempo;

@SuppressWarnings("unchecked")
public GlobalTimes() {
tempo = new ArrayList();
}

public List getTempo() {
return tempo;
}
public void setTempo(List tempo) {
this.tempo = tempo;
}

public long total(){
long tot = 0;
for(Iterator it = tempo.iterator();it.hasNext();){
Long aux = (Long)it.next();
tot += aux;
}
return tot;
}

}


PopulateMap.java

import java.util.Map;

public class PopulateMap {

@SuppressWarnings("unchecked")
public static void populate(Map map){
for(int i=0;i<=TestConstantes.totElementos;i++){ map.put(i, i * 0.25); } } }


TestConstantes.java

public class TestConstantes {

public static final int totElementos = 300000;

}


MapReader.java

import java.util.Map;

public class MapReader {

private static ThreadReader tr1 = null;
private static ThreadReader tr2 = null;
private static ThreadReader tr3 = null;

public static void read(Map m,String name,GlobalTimes gt){
tr1 = new ThreadReader(m,gt);
tr1.start();

tr2 = new ThreadReader(m,gt);
tr2.start();

tr3 = new ThreadReader(m,gt);
tr3.start();

while(true){
if (isOver(tr1, tr2, tr3)){
break;
}
}
System.out.println("**** Tempo Total: " + name + ": {Tempo de leitura: " + gt.total() + "} ");

}

private static boolean isOver(ThreadReader tr1,ThreadReader tr2,ThreadReader tr3){
return ( (!tr1.isAlive()) && (!tr2.isAlive()) && (!tr3.isAlive()) );
}

}


class ThreadReader extends Thread{

private Map map;
private GlobalTimes gt = null;
public ThreadReader(Map map,GlobalTimes gt) {
this.map = map;
this.gt = gt;
}

@Override
public void run() {

long init = System.currentTimeMillis();

@SuppressWarnings("unused")
String test = "";

for(int i=0;i<testconstantes.totelementos;i++){ object="" obj="map.get(i);" test="obj" 1="" double="" diff="(System.currentTimeMillis()" new="">




HashMapTest.java


import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class HashMapTest {

public static void main(String[] args) {
testAsSyncronmizedCollections();
testAsSyncronmizedConmcurrent();
}

private static void testAsSyncronmizedCollections(){

Map map = Collections.synchronizedMap(new HashMap() );
PopulateMap.populate(map);
GlobalTimes gt = new GlobalTimes();
MapReader.read(map,"testAsSyncronmizedCollections",gt);

}

private static void testAsSyncronmizedConmcurrent(){

Map map = new ConcurrentHashMap();
PopulateMap.populate(map);
GlobalTimes gt = new GlobalTimes();
MapReader.read(map,"testAsSyncronmizedConmcurrent",gt);

}

}


Moral da História: use sempre ConcurrentHashMap :)

Popular posts from this blog

Telemetry and Microservices part2

Installing and Running ntop 2 on Amazon Linux OS

Fun with Apache Kafka