Java面试那点事——基础200113

1.HashMap 和 Hashtable 有什么区别?HashMap 和 HashSet 呢?

HashMap 和 Hashtable 区别:

  • hashmap线程不安全、hashtable线程安全
  • hashmap继承自abstractmap、hashtable继承dictionary
  • hashmap允许存储null键值(存一个null键和多个value是null)、hashtable不允许
  • hashtable直接使用hashcode,hashmap用扰动函数处理hashcode(hashcode右移16位在与原hashcode异或操作,为了减少hashcode冲突)
  • hashmap初始容量16,hashtable11
  • hashmap扩容old*2;hashtable扩容old*2+1

hashset:

  • 底层实现是hashmap,因为hashset内部元素不能相同,所以存储方式为hashmap的key值。
  • 需要重写hashcode函数和equals函数,通过hashcode直接定位到地址,在通过equals比较对象。
  • 元素无序

2.final 关键字用于什么场景?

  • 字段不可修改,引用不可修改地址
  • 方法不能重写
  • 类不能继承

包含final域的对象的引用和读这个final域,不能重排序;构造函数对final域的写入和这个对象的引用被赋值,不能重排序。

使用场景:

  • 不可改变域
  • 多线程使用场景,使用final关键字或者:synchronized、volatile、锁

3.ConcurrentHashMap 如何实现线程同步?

hashmap的线程安全版,引入segment,每一个segment都是线程安全的,相当于一个hashtable,因此,ConcurrentHashMap也不允许出现null。这样就把整个类锁变成了局部锁,用哪一个segment就给哪一个segment加锁。减少竞争,提高效率。

对于jdk1.8的改进:

  • 取消的segment,转而采用数组元素作为锁。把锁的粒度从多个node变成一个node,进一步减少锁竞争
  • 链表大于8的时候转化为红黑树

实现线程同步:
元素Node,字段修饰为final和volatile,采用乐观锁CAS,和分而治之的思想

  • put操作和初始化操作:

    • volatile字段,标识位,表示当前是否有线程在初始化,volatile字段保证了所有线程的可见。
    • CAS机制,保证只有一个线程能够初始化
  • size()/判断大小
    首先通过CAS机制,如果没有线程竞争,直接递增count,失败就初始化桶,每一个桶并发的记录(同样是CAS机制,最大程度利用并发),如果桶计数频繁失败就扩容桶。


4.Map 遍历的两种方式?

keyset和entryset,前者是获得key的集合,后者是获得key-value的集合,返回的都是set视图,因为set有迭代器iterator可以用,通过iterator.next来遍历。

发布了147 篇原创文章 · 获赞 835 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/qq_33945246/article/details/103967581