首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

果然是快手,面试问的很深啊...

数组的每个位置是一个链表,当发生哈希冲突时,新元素会被添加到链表的末尾。...元素数量下降长会变回链表吗? 在 JDK 8 中的 HashMap 中,当元素数量减少时,可能会将红黑树重新转换回链表,这是为了避免维持一个过大的红黑树所带来的额外开销。...容易出现死循环: 在扩容时,多线程同时进行插入操作可能导致链表形成环形结构,进而造成死循环。...引入了 Node 数组,使用 CAS 操作进行元素的插入和修改,同时在必要时使用 synchronized 进行并发控制。 CAS 操作: 使用 CAS 操作代替了分段锁,减少了锁的竞争。...如果需要注入的属性是一个代理对象(例如 AOP、事务等),此时会先将未完成填充的对象暂时放入第二级缓存中,然后继续创建其他 Bean。 解决循环依赖: 当容器发现循环依赖时,会尝试解决它。

14310

Java 泛型详解

下面这个例子中,我们创建了一个泛型类Reader,然后在f1()中当我们尝试Fruit f = fruitReader.readExact(apples);编译器会报错,因为List与List...extends T>的用法,利用它我们可以从list里面get元素,那么我们可不可以往list里面add元素呢?我们来尝试一下: ? 答案是否定,Java编译器不允许我们这样做,为什么呢?...当我们尝试add一个Apple的时候,flist可能指向new ArrayList(); 当我们尝试add一个Orange的时候,flist可能指向new ArrayList元素了,但是使用super的坏处是以后不能get容器里面的元素了,原因很简单,我们继续从编译器的角度考虑这个问题,对于List错误假如出现才实际的应用场景中,将非常难以察觉。 如果你对上面这一点还抱有怀疑的话,可以尝试运行下面这段代码: ?

68750
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    Java面试题:HashMap为什么线程不安全、ConcurrentHashMap原理、ConcurrentHashMap与HashMap区别、Map总结

    中,HashMap扩容时使用头插法插入元素。...线程一:继续执行的时候就会出现死循环的问题。线程一先将A移入新的链表,再将B插入到链头,由于另外一个线程的原因,B的next指向了A,所以B->A->B,形成循环。...1.3 jdk1.8中的线程不安全——数据覆盖在jdk1.8中对HashMap进行了优化,在发生hash碰撞,不再采用头插法方式,而是直接插入链表尾部 即尾插法,保持了链表元素的顺序,解决了扩容造成的死循环...= 0) { // 如果链表元素个数达到了8,则尝试树化 // 因为上面把元素插入到树中时,binCount只赋值了2,并没有计算整个树中元素的个数...当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标存储时,如果出现hash值相同的key,此时有两种情况。

    18310

    Java集合泛型面试题(含答案)

    方法返回一个列表 ArrayList底层的实现是Array, 数组扩容实现 LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于 ArrayList...7、Map有什么特点 以键值对存储数据 元素存储循序是无序的 不允许出现重复键 8、集合类存放于 Java.util 包中, 主要有几 种接口 主要包含set(集)、 list(列表包含 Queue)和...当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。...大方向上, HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。...类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是 Object。如果指定了类型参数的上界的话,则使用这个上界。把代码中的类型参数都替换成具体的类。

    1.2K30

    Java 并发(9)ConcurrentHashMap 源码分析

    这种方法虽然简单,但导致了一个问题,那就是在同一时间内只能由一个线程去操作哈希表。即使这些线程都只是进行读操作也必须要排队,这在竞争激烈的多线程环境中极为影响性能。...定位分段锁和元素 可以看到分段锁和元素的定位都是通过元素的哈希码来决定的。定位分段锁是取哈希码的高位值 (从 32 位处取起),定位元素是取的哈希码的低位值。...现在有个问题,它们一个从 32 位的左端取起,一个从 32 位的右端取起,那么会在某个时刻产生冲突吗?...使用 getObjectVolatile 方法读取数组元素需要先获得元素在数组中的偏移量,在这里根据哈希码计算得到分段锁在数组中的偏移量为 u,然后通过偏移量 u 来尝试读取分段锁。...由于在构造 ConcurrentHashMap 时没有对 Segment 数组中的元素初始化,所以可能读到一个空值,这时会先通过 ensureSegment 方法新建一个分段锁。

    62110

    Java 并发编程之 ConcurrentHashMap 源码分析(小长文)

    这种方法虽然简单,但导致了一个问题,那就是在同一时间内只能由一个线程去操作哈希表。即使这些线程都只是进行读操作也必须要排队,这在竞争激烈的多线程环境中极为影响性能。...定位分段锁是取哈希码的高位值(从32位处取起),定位元素是取的哈希码的低位值。现在有个问题,它们一个从32位的左端取起,一个从32位的右端取起,那么会在某个时刻产生冲突吗?...使用getObjectVolatile方法读取数组元素需要先获得元素在数组中的偏移量,在这里根据哈希码计算得到分段锁在数组中的偏移量为u,然后通过偏移量u来尝试读取分段锁。...由于在构造ConcurrentHashMap时没有对Segment数组中的元素初始化,所以可能读到一个空值,这时会先通过ensureSegment方法新建一个分段锁。...从代码中可以知道新创建的数组长度为原数组的2倍(oldCapacity 中的所有元素移到新数组中,因此需要计算每个元素在新数组中的下标。

    68830

    Android面试问题汇总

    2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。...ConcurrentHashMap 1.8原理: 1.7 已经解决了并发问题,并且能支持 N 个 Segment 这么多次数的并发,但依然存在 HashMap 在 1.7 版本中的问题:那就是查询遍历链表效率太低...hashmap的键值使用时,就会出现我们认为的同一对象,却因为hash值不同而导致hashmap中存了两个对象,从而才需要进行hashcode方法的覆盖。...2、LinkedBlockingQueue 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。...3.有界队列满了之后,如果poolSize 时,会尝试new 一个Thread的进行救急处理,立马执行对应的runnable任务。

    38610

    Q&A:Java

    在HashSet中,会导致都能添加成功,那么HashSet中会出现很多重复元素,HashMap也是同理(因为HashSet的底层就是通过HashMap实现的),会出现大量相同的Key。...Java编译器是通过先检查代码中泛型的类型,然后在进行类型擦除,再进行编译。 编译时,检查添加元素的类型,更安全,减少了类型转换次数,提高效率。...创建时如果给定了初始容量,则扩充为2的幂次方大小。插入元素后如果链表长度大于阈值(默认为8),先判断数组长度是否小于64,如果小于,则扩充数组,反之将链表转化为红黑树,以减少搜索时间。...创建时如果给定了初始容量,则扩充为2的幂次方大小。插入元素后如果链表长度大于阈值(默认为8),先判断数组长度是否小于64,如果小于,则扩充数组,反之将链表转化为红黑树,以减少搜索时间。...1、开放地址法:也称为线性探测法,就是从发生冲突的位置开始,按照一定次序(顺延)从hash表找到一个空闲位置,把发生冲突的元素存到这个位置。

    63120

    深度解析HashMap:探秘Java中的键值存储魔法

    桶可以使用数组或链表来实现。在数组实现中,每个桶是一个数组元素,可以直接通过索引访问。在链表实现中,每个桶是一个链表,用于存储哈希冲突的元素。...开放寻址法: 如果发生冲突,就尝试在哈希表中的其他位置寻找空槽,并将键值对插入到找到的第一个空槽中。这可能涉及线性探测、二次探测等方法。...当发生哈希冲突时,该方法会尝试在散列表中的其他位置找到一个空的槽来存放冲突的元素。这可以通过线性探测、二次探测等方式来实现。...数据迁移: 将元素重新分配到新数组时,可能会出现多个元素映射到新数组的同一位置的情况(发生哈希碰撞)。在这种情况下,新数组的每个位置通常是一个链表或树结构,用于存储多个映射到相同位置的元素。...ConcurrentHashMap 主要有以下特点和优势:分段锁机制:ConcurrentHashMap 内部使用了分段锁(Segment),每个分段上都有一个锁,不同的键值对会被映射到不同的分段上,这样在多线程操作时只会锁住某个分段而不是整个结构

    13310

    对线面试官 - Java基础面试题【一】

    从接口角度来说,两者都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用 面试官:可以,但是上述List并非是线程安全的。...最后当所有元素都转移完了之后,将新数组赋值给HashMap对象的table属性即可 JDK1.8版本: 会先生成新数组 接着会遍历老数组中每个位置上的链表或红黑树 然后会进行判断如果是链表,则直接将链表中的每个元素重新计算下标...如果该位置下的元素个数没有超过8,那么则生成一个链表,并将链表的头节点添加到新数组的对应位置上 最后当所有元素转移完了之后,会将新数组赋值给HashMap对象的table属性 面试官:不错,HashMap...中的put方法进行的,而当前HashEntry已经使用了Segment对象作为锁来保证线程安全,进而保证了扩容的线程安全 JDK1.8中: 引入了红黑树的数据结构,且不再使用分段锁,改用Node数组 直接在散列表的每个头节点上使用...,扩容之前也先生成一个新的数组 在转移数组时,先将原数组分组,将每组分给不同的线程来进行元素的转移,每个线程负责一组或多组的元素转移工作。

    14430

    死磕 java集合之ConcurrentHashMap源码分析(一)

    轻量级锁,是指当锁是偏向锁时,被另一个线程所访问,偏向锁会升级为轻量级锁,这个线程会通过自旋的方式尝试获取锁,不会阻塞,提高性能。...(3)volatile(非锁) java中的关键字,当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。...(5)分段锁 分段锁,是一种锁的设计思路,它细化了锁的粒度,主要运用在ConcurrentHashMap中,实现高效的并发操作,当操作不需要更新整个数组时,就只锁数组中的一项就可以了。...= 0) { // 如果链表元素个数达到了8,则尝试树化 // 因为上面把元素插入到树中时,binCount只赋值了2,并没有计算整个树中元素的个数...; (4)如果待插入的元素所在的桶不为空且不在迁移元素,则锁住这个桶(分段锁); (5)如果当前桶中元素以链表方式存储,则在链表中寻找该元素或者插入元素; (6)如果当前桶中元素以红黑树方式存储,则在红黑树中寻找该元素或者插入元素

    43230

    Java泛型你看这篇文章就对了

    extends Fruit> flist = new ArrayList(); 当我们尝试add一个Apple的时候,flist可能指向new ArrayList(); 当我们尝试add...一个Orange的时候,flist可能指向new ArrayList(); 当我们尝试add一个Fruit的时候,这个Fruit可以是任何类型的Fruit,而flist可能只想某种特定类型的Fruit,...,但是使用super的坏处是以后不能get容器里面的元素了,原因很简单,我们继续从编译器的角度考虑这个问题,对于List list,它可以有下面几种含义: List list = new ArrayList(); 当我们尝试通过list来get一个Apple的时候,可能会get得到一个Fruit,这个Fruit可以是Orange...类似这样的错误假如出现才实际的应用场景中,将非常难以察觉。

    84720

    Java 基础面试总结

    当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,在IntegerCache 范围内直接引用常量池中的对象,不会新创建对象。...当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进 行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。...,然后数组中每个元素是一个单向链表.实体是嵌套类 Entry 的实例,Entry 包含四个属性:key, value, hash 值和用于单向链表的 next java 8 : Java8 对 HashMap...在 Java8 中,当链表中的元素超过了 8 个以后, 会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。 HashMap 默认的初始化大小为16。...null,到此也就结束了(跟线程二一样的过程),但是,由于线程二扩容的原因,将 B.next=A,所以,这里继续复制A,让 A.next=B,由此,环形链表出现:B.next=A; A.next=B.

    59120

    深入理解Java中的ConcurrentHashMap:原理与实践

    当我们需要添加一个键值对时,可以使用putIfAbsent()方法,这个方法会在键不存在时才添加键值对,从而避免覆盖已存在的值。...当我们需要增加一个键的计数时,可以使用compute方法,这个方法会在键存在时增加计数,否则初始化计数为1。...当我们插入一个新元素时,会根据元素的哈希值确定要插入的Segment,然后再在该Segment的HashEntry数组中找到合适的位置插入元素。...现在的数据结构是一个Node数组,每个Node可以是一个链表或者红黑树。 当链表长度超过TREEIFY_THRESHOLD(默认为8)时,链表会转为红黑树。...这段代码实现了ConcurrentHashMap中的rehashing过程,即在扩容时将旧哈希表中的元素重新计算哈希值并放入新的哈希表中。

    50410

    ConcurrentHashMap(JDK8)

    同时因为一个Segment内部存在一个HashEntry数组,所以和HashMap对比来看,相当于分段了,每段里面是一个小的HashMap,每段公用一把锁,同时在ConcurrentHashMap的构造方法中是可以设置分段的数量的...JDK8中使用synchronized加锁时,是对链表头结点和红黑树根结点来加锁的,而ConcurrentHashMap会保证,数组中某个位置的元素一定是链表的头结点或红黑树的根结点,所以JDK8中的ConcurrentHashMap...在对某个桶进行并发安全控制时,只需要使用synchronized对当前那个位置的数组上的元素进行加锁即可,对于每个桶,只有获取到了第一个元素上的锁,才能操作这个桶,不管这个桶是一个链表还是红黑树。...首先,JDK8中是支持多线程扩容的,JDK8中的ConcurrentHashMap不再是分段,或者可以理解为每个桶为一段,在需要扩容时,首先会生成一个双倍大小的数组,生成完数组后,线程就会开始转移元素,...,某个线程在调用ConcurrentHashMap对象的put操作时,会先通过CAS去修改baseCount的值,如果CAS修改成功,就计数成功,如果CAS修改失败,则会从CounterCell数组中随机选出一个

    13.9K76

    每天都在用 Map,这些核心技术你知道吗?

    新添加的元素通过取模的方式,定位 Table 数组位置,然后将元素加入链表头部,这样下次提取时就可以快速被访问到。...访问数据时,也是通过取模的方式,定位数组中的位置,然后再遍历链表,依次比较,获取相应的元素。 如果 HasMap 中元素过多时,可能导致某个位置上链表很长。...从源码出发,并发过程数据丢失的原因有以下几点: 并发赋值时被覆盖 ? 并发的情况下,一个线程的赋值可能被另一个线程覆盖,这就导致对象的丢失。 size 计算问题 ?...这就是一个典型的热点数据更新问题。 这个问题实际原因是因为多线程并发抢夺行锁导致,那如果有多把行锁,是不是就可以降低锁冲突了那?...ConcurrentHashMap 分段锁的经典思想,我们可以应用在热点更新的场景,提高更新效率。 不过一定要记得,当我们引入新方案解决问题时,必定会引入新的复杂度,导致其他问题。

    50330

    详解ConcurrentHashMap及JDK8的优化

    由于HashMap在并发中会出现一些问题,所以JDK中提供了并发容器ConcurrentHashMap。有关HashMap并发中的问题和原理,强烈建议查看这篇文章进行复习。...数据结构:取消了Segment分段锁的数据结构,取而代之的是Node数组+链表+红黑树的结构,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。...链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。...查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)。...当你调用他的next()方法来获取下一个元素时,迭代器将会用到这个计数器。

    1.3K50
    领券