HashMap 原理和源码分析

本文深入探讨了HashMap的工作原理,包括其存储结构、容量调整机制、数据获取及插入操作流程。此外,还讨论了多线程环境下访问HashMap可能遇到的问题及其解决办法。

1. HashMap 存储结构

采用哈希表来存储数据。结构如下:

它在内部维护了一个Entry数组

transient Entry<K,V>[]table;


Entry 的结构如下:


static class Entry<K,V>implementsMap.Entry<K,V>{
  final K key;
  V value;
  Entry<K,V> next;
  int hash;
}


2. 容量的调整

HashMap 中table 的大小是动态变化的,并可以设置一装载因子(load factor)。当HashMap中元素总量超过阈值时(capacity*loadFactor),再向其中新增元素将会重新分配一个table 替换当前的。Table大小一定是2的幂,比如最小是16,然后增长的话会调整到32,64,128…,直到最大 map 大小2^30。

2.1 存储位置

每个元素根据其 hash的不同存储在 table 数组的不同位置:

static int indexFor(int h,int length){
    return h &(length-1);
}
2.2 获取数据

final Entry<K,V>getEntry(Object key){
    int hash = (key== null)? 0:hash(key);
    for(Entry<K,V>e=table[indexFor(hash,table.length)];e!=null;e=e.next){
        Object k;
        if(e.hash ==hash &&((k=e.key)==key||(key!=null&&key.equals(k))))
        return e;
    }
    return null;
}


获取数据时直接找到相应 index位置的链表,遍历链表找到对应元素。

2.3 put 操作

如果已经有对应 key的元素,则用新元素替代,并返回旧元素。否则返回 null

Put的时候判断当前元素数是否达到阈值,如果达到需要resize table。先判断大小是否达到最大限制,没有的话 capacity 翻倍。然后将旧 table中的元素重新计算 bucket位置放入新table

void resize(int newCapacity){
    Entry[] oldTable=table;
    Int oldCapacity= oldTable.length;
    if(oldCapacity ==MAXIMUM_CAPACITY){
    threshold=Integer.MAX_VALUE;
    return;
    }
 
    Entry[] newTable= newEntry[newCapacity];
    Boolean oldAltHashing= useAltHashing;
    useAltHashing|=sun.misc.VM.isBooted()&&
        (newCapacity>=Holder.ALTERNATIVE_HASHING_THRESHOLD);
    Boolean rehash= oldAltHashing^ useAltHashing;
    transfer(newTable,rehash);
    Table = newTable;
    threshold = (int)Math.min(newCapacity*loadFactor,MAXIMUM_CAPACITY+1);
}

3. 多线程访问问题

HashMap访问迭代器的时候可能抛出 ConcurrentModificationException

 

final Entry<K,V> nextEntry(){
    if(modCount!=expectedModCount)
        throw new ConcurrentModificationException();
    Entry<K,V>e=next;
    if(e==null)
        throw new NoSuchElementException();
 
    if((next=e.next)==null){
        Entry[]t=table;
        while(index<t.length&&(next=t[index++])==null)
            ;
    }
    current = e;
    return e;
}

modCount在每次HashMap发生结构性变化的时候都会改变(新增、删除元素,rehash),而 expectedModCount 是迭代器维护的,并不会随着HashMap结构变化而改变。

需要注意,并不是一定是多线程访问才会触发 ConcurrentModificationException。在单线程的访问中,迭代器操作中不能直接通过HashMap.put HashMap.remove操作更改 HashMap。如果确实需要删除,可以通过迭代器提供的 remove方法删除元素,迭代器的 remove方法会修改expectedModCount。当然,多线程访问还是一定会有问题的。

public voidremove(){
    if(current==null)
        throw newIllegalStateException();
    if(modCount!=expectedModCount)
        throw newConcurrentModificationException();
    Objectk=current.key;
    current=null;
    HashMap.this.removeEntryForKey(k);
    expectedModCount =modCount;
}

4. 其他

还有几点需要注意

1. 初始化时,如果可以提前预知HashMap 的大小,可以指定一个initialSize,避免因为size 过小导致put 的时候多次 resize 操作

2. HashMap 最大size 大小为 1<<30, 也就是1G。因此需要注意向Map 中放入的内容一定不要超过1G。


基于分布式模型预测控制的多个固定翼无人机一致性控制(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制的多个固定翼无人机一致性控制”展开,采用Matlab代码实现相关算法,属于顶级EI期刊的复现研究成果。文中重点研究了分布式模型预测控制(DMPC)在多无人机系统中的一致性控制问题,通过构建固定翼无人机的动力学模型,结合分布式协同控制策略,实现多无人机在复杂环境下的轨迹一致性稳定协同飞行。研究涵盖了控制算法设计、系统建模、优化求解及仿真验证全过程,并提供了完整的Matlab代码支持,便于读者复现实验结果。; 适合人群:具备自动控制、无人机系统或优化算法基础,从事科研或工程应用的研究生、科研人员及自动化、航空航天领域的研发工程师;熟悉Matlab编程基本控制理论者更佳; 使用场景及目标:①用于多无人机协同控制系统的算法研究与仿真验证;②支撑科研论文复现、毕业设计或项目开发;③掌握分布式模型预测控制在实际系统中的应用方法,提升对多智能体协同控制的理解与实践能力; 阅读建议:建议结合提供的Matlab代码逐模块分析,重点关注DMPC算法的构建流程、约束处理方式及一致性协议的设计逻辑,同时可拓展学习文中提及的路径规划、编队控制等相关技术,以深化对无人机集群控制的整体认知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值