在解决hash collision问题的时候发现resin4.0.7和resin4.0.26中临时保存form参数的Map实现类不同。4.0.7使用的java.util.HashMap,resin4.0.26使用的是自定义的com.caucho.util.HashMapImpl ,参考代码:
private V putImpl(K key, V value)
{
Object item = null;
int hash = key.hashCode() & this._mask;
int count = this._values.length;
for (; count > 0; count--) {
item = this._values[hash];
if (item == null) {
this._keys[hash] = key;
this._values[hash] = value;
this._size += 1;
return null;
}
if (this._keys[hash].equals(key)) {
this._values[hash] = value;
return item;
}
hash = hash + 1 & this._mask;
}
throw new IllegalStateException();
}
put操作的hash定位、collision解决方法和HashMap的put方式完全不同,当时很疑惑。。。
今天在看Trove的时候,才知道HashMapImpl使用的Open Addressing.Linear Probing方式来解决Hash Collision问题的。
关于Open Addressing的详细介绍:
http://hi.baidu.com/%B7%AB%C2%DE/blog/item/3e119f17c7151c32dd540193.html
http://www.ibm.com/developerworks/cn/java/j-perf09284.html
优缺点:
“Trove 映射是采用开放选址而不是链接来实现的。在 Java 核心集合类中,多数映射都是使用链接实现,就是说如果多个键映射到表中的同一索引位置,则索引位置保存一个链表,其中存放映射到该位置的所有元素。开放选 址映射则假设表中邻近的位置存在没有使用的索引。如果目标位置已经被占用,映射实现就查看附近的几个位置找到一个没有使用的位置。这种方法不需要链表节 点,因此 Trove 映射和相同的核心集合类相比占用的内存更少。使用开放选址必须保证有足够的空闲索引,否则可能影响性能。(Trove 保持装载因子小于 0.5。)否则的话,开放选址的效率与链接基本相当,但多数情况下要好于后者。
开放选址的另一个优点是实现中不需要链表节点对象,链表节点需要靠链接来实现。为什么特别强调这一点呢?基本上每个 JVM 版本都会改进对象创建和无用单元回收的性能,但是较多的对象总会带来更多的开销。对于任何特定的问题,Java 编程中能够减少对象数量的解决方案通常都有更好的效率,这是一个标准的性能权衡问题,每个有经验的性能优化人员都知道。开放选址使用更少的对象来维护映射 结构,这意味着 Trove 映射在多数情况下比核心 Java 映射更有效,也更小。值得一提的是,最近越来越多的 Java 核心 Map 实现开始使用开放选址(比如 IdentityHashMap 类)。现有的其他核心 Java Map 实现最终也可能改为使用开放选址,虽然我们可能不那么关心,因为如果需要开放选址的实现,使用 Trove 就可以了。”
其中IdentityHashMap.hash方法保证每次put操作,相同hashcode的key所被分配的地址是最后未被使用的位置,否则就需要resize了