乐天堂fun88 - 轻松学习从此开始!    

乐天堂fun88

Java1234官方群25:
Java1234官方群25:838462530
        
()

SpringBoot打造企业级进销存

Java1234 VIP课程

领取微信扫码登录Java实现视频教程

Java1234至尊VIP(特价活动)

阿里Java最新版面试集锦2020 PDF 下载


分享到:
时间:2020-10-09 09:14来源:http://www.51qzml.com 作者:转载  
阿里Java最新版面试集锦2020 PDF 下载
失效链接处理
阿里Java最新版面试集锦2020 PDF 下载

本站整理下载:
链接: 
提取码:9pyg 
 
 
相关截图:
 
主要内容:

⼀、红⿊树的特性
(1)每个节点或者是⿊⾊,或者是红⾊。
(2)根节点是⿊⾊。
(3)每个叶⼦节点(NIL)是⿊⾊。 [注意:这⾥叶⼦节点,是指为空(NIL或NULL)
的叶⼦节点!] (4)如果⼀个节点是红⾊的,则它的⼦节点必须是⿊⾊的。
(5)从⼀个节点到该节点的⼦孙节点的所有路径上包含相同数⽬的⿊节点。
注意:
(01) 特性(3)中的叶⼦节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有⼀条路径会⽐其他路径⻓出俩倍。因⽽,红⿊树是相对是接近平
衡的⼆叉树。
红⿊树的应⽤⽐较⼴泛,主要是⽤它来存储有序的数据,它的时间复杂度是O(lgn),效率
⾮常之⾼。
例如,Java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内
存的管理,都是通过红⿊树去实现的。
******************************************************************** 
⼆、HashMap和HashTable的不同点
1 继承和实现⽅式不同
HashMap 继承于AbstractMap,实现了Map、Cloneable、
java.io.Serializable接⼝。
Hashtable 继承于Dictionary,实现了Map、Cloneable、
java.io.Serializable接⼝。
2 线程安全不同
Hashtable它是线程安全的,⽀持多线程。
⽽HashMap它不是线程安全的。
3 对null值的处理不同
HashMap的key、value都可以为null。
Hashtable的key、value都不可以为null。
4 ⽀持的遍历种类不同
HashMap只⽀持Iterator(迭代器)遍历。
⽽Hashtable⽀持Iterator(迭代器)和Enumeration(枚举器)两种⽅式遍
历。
5 通过Iterator迭代器遍历时,遍历的顺序不同
HashMap是“从前向后”的遍历数组;再对数组具体某⼀项对应的链表,从表
头开始进⾏遍历。
Hashtable是“从后往前”的遍历数组;再对数组具体某⼀项对应的链表,从表
头开始进⾏遍历。
6 容量的初始值 和 增加⽅式都不⼀样
HashMap默认的容量⼤⼩是16;增加容量时,每次将容量变为“原始容量
x2”。
Hashtable默认的容量⼤⼩是11;增加容量时,每次将容量变为“原始容量
x2 + 1”。
7 添加key-value时的hash值算法不同
HashMap添加元素时,是使⽤⾃定义的哈希算法。
Hashtable没有⾃定义哈希算法,⽽直接采⽤的key的hashCode()。
8 部分API不同
Hashtable⽀持contains(Object value)⽅法,⽽且重写了toString()⽅ 法;⽽HashMap不⽀持contains(Object value)⽅法,没有重写toString()
⽅法。
******************************************************************** 
三、ConcurrentHashMap为什么⽐HashTable性能好
ConcurrentHashMap 分段锁 Segment+HashEntry 
HashTable竞争同⼀个锁 Synchronized 
Segment类继承于ReentrantLock,主要是为了使用ReentrantLock的锁,
ReentrantLock的实现比 synchronized在多个线程争用下的总体开销小 
  既然ConcurrentHashMap使⽤分段锁Segment来保护不同段的数据,那么在插⼊和获
取元素的时候,必须先通过哈希算法定位到Segment。可以看到ConcurrentHashMap会⾸
先使⽤Wang/Jenkins hash的变种算法对元素的hashCode进⾏⼀次再哈希。
再哈希,其⽬的是为了减少哈希冲突,使元素能够均匀的分布在不同的Segment上,从⽽提⾼
容器的存取效率。
整个操作是先定位到段,然后委托给段的remove操作。当多个删除操作并发进⾏时,只要它
们所在的段不相同,它们就可以同时进⾏。
 由于put⽅法⾥需要对共享变量进⾏写⼊操作,所以为了线程安全,在操作共享变量时必须
得加锁。Put⽅法⾸先定位到Segment,然后在Segment⾥进⾏插⼊操作。插⼊操作需要经 历两个步骤,第⼀步判断是否需要对Segment⾥的HashEntry数组进⾏扩容,第⼆步定位添
加元素的位置然后放在HashEntry数组⾥。
• 是否需要扩容。在插⼊元素前会先判断Segment⾥的HashEntry数组是否超过容量
(threshold),如果超过阀值,数组进⾏扩容。值得⼀提的是,Segment的扩容判断⽐
HashMap更恰当,因为HashMap是在插⼊元素后判断元素是否已经到达容量的,如果到
达了就进⾏扩容,但是很有可能扩容之后没有新元素插⼊,这时HashMap就进⾏了⼀次
⽆效的扩容。
• 如何扩容。扩容的时候⾸先会创建⼀个两倍于原容量的数组,然后将原数组⾥的元素进⾏ 再hash后插⼊到新的数组⾥。为了⾼效ConcurrentHashMap不会对整个容器进⾏扩
容,⽽只对某个segment进⾏扩容。
get操作不需要锁。
除⾮读到的值是空的才会加锁重读,我们知道HashTable容器的get⽅法是需要加锁的,
那么ConcurrentHashMap的get操作是如何做到不加锁的呢?原因是它的get⽅法⾥将要使⽤
的共享变量都定义成volatile。
size()操作
  如果我们要统计整个ConcurrentHashMap⾥元素的⼤⼩,就必须统计所有Segment⾥
元素的⼤⼩后求和。Segment⾥的全局变量count是⼀个volatile变量,那么在多线程场景
下,我们是不是直接把所有Segment的count相加就可以得到整个ConcurrentHashMap⼤⼩
了呢?不是的,虽然相加时可以获取每个Segment的count的最新值,但是拿到之后可能累加
前使⽤的count发⽣了变化,那么统计结果就不准了。所以最安全的做法,是在统计size的时
候把所有Segment的put,remove和clean⽅法全部锁住,但是这种做法显然⾮常低效。
  因为在累加count操作过程中,之前累加过的count发⽣变化的⼏率⾮常⼩,所以
ConcurrentHashMap的做法是先尝试2次通过不锁住Segment的⽅式来统计各个Segment
⼤⼩,如果统计的过程中,容器的count发⽣了变化,则再采⽤加锁的⽅式来统计所有
Segment的⼤⼩。
  那么ConcurrentHashMap是如何判断在统计的时候容器是否发⽣了变化呢?使⽤
modCount变量,在put , remove和clean⽅法⾥操作元素前都会将变量modCount进⾏加
1,那么在统计size前后⽐较modCount是否发⽣变化,从⽽得知容器的⼤⼩是否发⽣变化。
************************************************************************************** 
四、ClassLoader的分类及加载顺序
   主要分4类,⻅下图橙⾊部分
   JVM类加载器:这个模式会加载JAVA_HOME/lib下的jar包
   扩展类加载器:会加载JAVA_HOME/lib/ext下的jar包
   系统类加载器:这个会去加载指定了classpath参数指定的jar⽂ 件
   ⽤户⾃定义类加载器:sun提供的ClassLoader是可以被继承
的,允许⽤户⾃⼰实现类加载器
   类加载器的加载顺序如图所示

 

------分隔线----------------------------
锋哥公众号


锋哥微信


关注公众号
【Java资料站】
回复 666
获取 
66套java
从菜鸡到大神
项目实战课程