`

HashMap 多线程 死循环 Java

阅读更多

HashMap 多线程 死循环 Java

HashMap,  众所周知,是线程不安全的。在多线程的情况下,在get() 非常有可能出现死循环。因为

HashMap采用链表解决Hash冲突,因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环。只 有一个线程对HashMap的数据结构进行操作,是不可能产生闭合的回路的。那就只有在多线程并发的情况下才会出现这种情况,那就是在put操作的时候, 如果size>initialCapacity*loadFactor,那么这时候HashMap就会进行rehash操作

public V put(K key, V value)
{
    ......
    //算Hash值
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    //如果该key已被插入,则替换掉旧的value (链接操作)
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;
    //该key不存在,需要增加一个结点
    addEntry(hash, key, value, i);
    return null;
}

 

检查容量是否超标addEntry

void addEntry(int hash, K key, V value, int bucketIndex)
{
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    //查看当前的size是否超过了我们设定的阈值threshold,如果超过,需要resize
    if (size++ >= threshold)
        resize(2 * table.length);
}

 如果现在size已经超过了threshold,那么就要进行resize操作,新建一个更大尺寸的hash表,然后把数据从老的Hash表中迁移到新的Hash表中

 

调整Hash表大小resize

void resize(int newCapacity)
{
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    ......
    //创建一个新的Hash Table
    Entry[] newTable = new Entry[newCapacity];
    //将Old Hash Table上的数据迁移到New Hash Table上
    transfer(newTable);
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}

 

当table[]数组容量较小,容易产生哈希碰撞,所以,Hash表的尺寸和容量非常的重要。一般来说,Hash表这个容器当有数据要插入时,都会检查容量有没有超过设定的thredhold,如果超过,需要增大Hash表的尺寸,这个过程称为resize。

多个线程同时往HashMap添加新元素时,多次resize会有一定概率出现死循环,因为每次resize需要把旧的数据映射到新的哈希表,这一部分代码在HashMap#transfer() 方法:

void transfer(Entry[] newTable)
{
    Entry[] src = table;
    int newCapacity = newTable.length;
    //下面这段代码的意思是:
    //  从OldTable里摘一个元素出来,然后放到NewTable中
    for (int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if (e != null) {
            src[j] = null;
            do {
                Entry<K,V> next = e.next;
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            } while (e != null);
        }
    }
}

 

分享到:
评论

相关推荐

    关于如何解决HashMap线程安全问题的介绍

    在多线程环境下,两个线程同时触发扩容可能导致循环链表的形成,从而引发死循环,这是一种严重的性能问题。 为了解决HashMap的线程不安全问题,我们可以采取以下几种策略: 1. 使用Collections.synchronizedMap()...

    疫苗:Java HashMap的死循环

    然而,在多线程环境中使用HashMap可能会导致死循环的问题。下面我们来分析HashMap的死循环原因。 首先,HashMap的数据结构是一个数组加链表的结构。每个数组元素是一个链表的头结点,每个链表节点包含了key-value对...

    高级程序员必会的HashMap的线程安全问题,适用于0~2年的.7z

    3. **死循环(死锁)**:在极端情况下,由于HashMap的迭代器依赖于table的状态,如果在迭代过程中table结构发生变化(比如resize),可能会造成迭代器陷入死循环。 为了解决这些问题,有以下几种策略: 1. **使用...

    HashMap源码分析系列-第四弹:HashMap多线程解决方案.docx

    ### HashMap多线程解决方案 #### 一、引言 在多线程环境下,Java的`HashMap`类在处理并发操作时容易出现线程安全问题。本文档深入探讨了`HashMap`在多线程环境中可能遇到的安全问题,并提出了一系列可行的解决方案...

    深入了解JAVA HASHMAP的死循环

    然而,由于HashMap不是线程安全的,因此在多线程环境下直接使用可能会引发一系列问题,其中之一就是所谓的"死循环"。本文将深入探讨这一主题。 首先,死循环问题通常发生在并发环境中,当多个线程同时修改HashMap时...

    hashmap-thread-test:测试 Java HashMap 是否是线程安全的

    然而,`HashMap`并非线程安全,这意味着在多线程环境中直接使用`HashMap`可能会导致数据不一致、并发问题,甚至程序崩溃。本项目“hashmap-thread-test”显然是为了测试和展示这一特性。 ### Java HashMap 的特性 ...

    基于Java HashMap的死循环的启示详解

    Java HashMap的死循环是一个在多线程环境下容易出现的问题,主要由于其内部的迭代器实现方式和并发操作不当引起。本文将深入分析这个问题,并探讨如何避免这类错误。 首先,Java HashMap在非线程安全的环境下,如果...

    Java系列深入解析Java多线程

    Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,从而提升系统效率。在现代计算环境中,多线程技术对于充分利用CPU资源、提高应用程序响应速度以及实现复杂并发控制至关重要。本文将深入探讨Java多...

    马士兵老师HashMap学习笔记

    当哈希冲突导致多线程环境下节点形成环状链表时,迭代器的next()方法将无法找到结束条件,从而引发死循环。为了避免这种情况,开发者需要在多线程环境下使用线程安全的数据结构,如ConcurrentHashMap,或者在单线程...

    java多线程设计模式

    Java多线程设计模式是Java开发中不可或缺的一部分,它涉及到并发编程的核心概念和技术。在现代计算机系统中,多线程并行处理任务已经成为提升效率的关键。本篇文章将深入探讨Java多线程设计模式,帮助你更好地理解和...

    java7-8中的 HashMap和ConcurrentHashMap全解析

    `HashMap`是非线程安全的,意味着在多线程环境下,多个线程同时操作`HashMap`可能会导致数据不一致或者死循环。因此,如果需要在并发环境中使用,必须使用同步机制,如`synchronized`关键字或`Collections....

    java,多线程实验.zip

    在Java编程语言中,多线程是核心特性之一,它允许程序同时执行多个独立的代码段,从而提高程序的效率和响应性。本实验旨在深入理解Java中的多线程概念,通过实践操作来掌握相关技术。 一、Java多线程基础 1. 线程与...

    java面试多线程高并发相关回家技巧(超经典)

    在Java编程领域,多线程和高并发是面试中经常被问到的重要知识点,也是大型系统设计的关键技术。本文将围绕“Java面试多线程高并发相关回家技巧”这一主题,深入探讨相关概念、原理以及面试中可能遇到的问题,帮助你...

    一线大厂Java多线程面试120题.pdf

    Java多线程是Java开发中的核心技能之一,尤其在面试中,对于一线大厂的面试者来说,深入理解和掌握多线程的相关知识点至关重要。以下是一些关键的Java多线程面试知识点: 1. **自旋锁**:自旋锁是一种等待机制,当...

    java7hashmap源码-backend-study:后端学习之路

    java7 hashmap源码 随着Java学习的不断深入,发现...多线程下,hashmap的resize()方法为什么容易出现死循环? 答: 其他面试题? 答: 并发 概述 :star::star: :star::star: 线程池 :star: AQS :star: 锁 ListenalbeFut

    java 面试题 java基础部分

    HashMap是非线程安全的,而在多线程环境下可能会遇到并发问题,如死循环和数据不一致。 3. **hashMap、hashTable、treeMap的区别**:HashMap允许键为null且不保证顺序;HashTable不允许null键值,且线程安全,但...

    Hashmap实现了Map接口的底层实现.docx

    HashMap在多线程环境中并不安全,因为其非线程安全的设计可能导致死循环。例如,在并发扩容时,可能产生环形链表。在这种情况下,尝试获取不存在的键时,可能会导致无限循环。因此,多线程场景推荐使用...

    HashMap资料.zip

    4. **线程安全**:HashMap本身不是线程安全的,如果在多线程环境下使用,需要使用Collections.synchronizedMap()方法或者ConcurrentHashMap。线程安全问题可能导致数据不一致或者死循环等问题。 5. **null键和值**...

Global site tag (gtag.js) - Google Analytics