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

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

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

12310

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<Apple...这样我们可以往容器里面添加元素,但是使用super的坏处是以后不能get容器里面的元素,原因很简单,我们继续编译器的角度考虑这个问题,对于List<?...类似这样的错误假如出现才实际的应用场景,将非常难以察觉。 如果你对上面这一点还抱有怀疑的话,可以尝试运行下面这段代码: ?

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

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,并没有计算整个树中元素的个数...当我们往HashMapput元素,利用key的hashCode重新hash计算出当前对象的元素在数组的下标存储,如果出现hash值相同的key,此时有两种情况。

4310

Java 并发(9)ConcurrentHashMap 源码分析

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

60110

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

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

66630

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

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

1.1K30

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

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

12830

Q&A:Java

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

60220

Android面试问题汇总

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

30610

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

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

42030

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...类似这样的错误假如出现才实际的应用场景,将非常难以察觉。

83320

ConcurrentHashMap(JDK8)

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

13.8K76

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.

55420

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

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

48430

java泛型详解

如果我们在对一个对象所赋的值不符合其泛型的规定, 就会编译报错 避免强转: 比如我们在使用List, 如果我们不使用泛型, 当List取出元素, 其类型会是默认的Object, 我们必须将其向下转型为...但是,我们可以保证不管参数是什么泛型,里面的元素肯定是Number或者其子类,所以,List获取一个Number元素的get()方法是允许的。...,但是使用super的坏处是以后不能get容器里面的元素,原因很简单,我们继续编译器的角度考虑这个问题,对于List list = new ArrayList(); 当我尝试通过list来get一个Apple的时候,可能会get得到一个Fruit,这个Fruit可以是Orange等其他类型的...类似这样的错误假如出现才实际的应用场景,将非常难以察觉。

31610

详解ConcurrentHashMap及JDK8的优化

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

1.1K50

​让我们来看看,多线程下的Map是如何实现线程安全的

ConcurrentHashMap ConcurrentHashMap的出现就是为了提高Map的并发能力,而且同HashMap一样在DJK1.8也对其做出来较大的改造,那么接下来就让我们jdk1.7...segment的线程安全的:首次进入该方法尝试获取该segment的锁,若获取失败,则调用 scanAndLockForPut(key, hash, value)方法来尝试自旋获取锁,如果自旋的次数达到了...在对数组扩容的时候,当树中元素个数小于或等于6,将树转成链表 从上图中我们可以看出JDK1.8使用Node来代替HashEntry。...而且我们源码也可以看出,其value值和next使用volatile修饰,保证内存可见性,以及禁止指令重排。...(这里使用的Synchronized以及经过优化,是升级过后的锁,其性能得到了提升) 总结: 数据结构:取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构,提高了遍历的效率,遍历链表

40910
领券