Collections.synchronizedMap VS ConcurrentHashMap
Antigamente até a verão 1.4.* do java quando precisávamos de uma Map sincronizado, normalmente faríamos isso:
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:
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
PopulateMap.java
TestConstantes.java
MapReader.java
HashMapTest.java
Moral da História: use sempre ConcurrentHashMap :)
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 {
Listtempo;
@SuppressWarnings("unchecked")
public GlobalTimes() {
tempo = new ArrayList();
}
public ListgetTempo() {
return tempo;
}
public void setTempo(Listtempo) {
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 :)