HashMap不是线程安全的,在并发的情况下可能会引起CPU利用率达100%,这点是需要引起重视的。
多线程的情况下应该使用ConcurrentHashMap,ConcurrentHashMap是JDK1.5之后引入的类。
多线程的情况下如果要使用HashMap,则需要自己做同步处理,使用Collections类的synchronizedMap静态方法。
ArrayList是Vector的“裸奔”版本,不是线程安全的,多线程时应该使用Vector。
即使使用线程安全的类,同步的处理还是需要自己处理。
public MapTest{
private Map map = Collections.synchronizedMap(new HashMap());
private synchronized void put(){
map....
}
}
看似是做了同步,但是synchronized的对象是MapTest,而不是map,这样的同步处理是失败的。应该下面这样来处理
public MapTest{
private Map map = Collections.synchronizedMap(new HashMap());
private void put(){
synchronized(map ){
map....
}
}
}
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
在Hashtable中,无论是key还是value都不能为null。
HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。
java5中新增了ConcurrentMap接口和它的一个实现类ConcurrentHashMap。ConcurrentHashMap提供了和Hashtable以及SynchronizedMap中所不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。
上面说到的16个线程指的是写线程,而读操作大部分时候都不需要用到锁。只有在size等操作时才需要锁住整个hash表。