1、先测了一下多线程条件下hashmap,结果果然是不行啊,cpu在100%左右浮动,永远也执行不完put和get操作。
2、在能大概估计hashmap所要容纳的键值数量的情况下,可以直接用构造函数生成一定大小的map,这样避免在扩容的过程中不断的rehash成本。
3、具体代码见最后:i表示提交的线程数量,m表示每个线程执行的put和get次数。
1)如果只用单线程运行,线程内容修改如下:
public void run() { // TODO Auto-generated method stub for(int m=0;m<2000000;m++){ String temp=":"+String.valueOf(m); map.put(temp, String.valueOf(m)); map.get(temp); if(m%50000==0){ System.out.println(m); } } }这种场景下,在我的机器上一般打印到170万左右的时候就不再继续打印。这时候hashmap内总共的键值对有170万左右
2)当i=5000,m=1000时,线程池在完成了1600多个线程之后就再也无法完成剩下的线程,此时hashmap的键值对容量大概是160万左右。
同样的i=5000,m=1000时,如果把run函数里的key写成每个进程间都有重复的话(即把temp拼接的第一位去掉)就可以正常运行下去,结果的键值对容量是1000
3)当i=10000,m=100的时候,在我的机器上可以在2秒左右执行完成,结果的键值对数量是100万
当i=100000,m=10的时候,在我的机器上也是2秒左右,结果的键值对数量也是100万
当i=100000,m=20的时候,一般执行到90000多个线程的时候就执行不下去了。
但如果把i改为20000,m=100的时候,则一般只执行到17000多个线程就执行不下去了,此时hashmap里键值对数量大概为170万左右
综上:
对concurrenthashmap而言,应付数多线程并发执行在效率上没什么太大的问题,两秒多一点时间可以执行读取操作各100万次无鸭梨;
只是在键值对数量超过一定数量的时候就会出现问题了,在我的机器上现在是170万左右。
代码如下:
public class HashMapTest { public static Map<String,String> map=new ConcurrentHashMap<String,String>(6000000); /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ThreadPoolExecutor te=(ThreadPoolExecutor)Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1); HashMapTest ht=new HashMapTest(); long start=System.currentTimeMillis(); for(int i=0;i<5000;i++){ te.execute(ht.new Task(i)); } while(te.getActiveCount()!=0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(te.getCompletedTaskCount()); } te.shutdown(); System.out.println("Time:"+(System.currentTimeMillis()-start)); } class Task implements Runnable{ public int i; public Task(int i){ this.i=i; } @Override public void run() { // TODO Auto-generated method stub for(int m=0;m<1000;m++){ String temp=String.valueOf(i)+":"+String.valueOf(m); map.put(temp, String.valueOf(m)); map.get(temp); } } } }