java 面试题积累

1、ngix的负载均衡机制

(1)轮询(默认)逐一访问后端服务器,每一个请求按顺序逐一分配到不同的后端服务器,如果后端服务器down掉了,则能自动剔除

(2)ip_hash 请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

  (3) weight是设置权重,用于后端服务器性能不均的情况,访问比率约等于权重之比

(4)fair(第三方)、这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。

(5) url_hash(第三方)此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

2、HashMap的底层原理

HashMap 是一种存储高校但是不保证有序的容器,它的数据结构为"数组+链表/红黑树"的结构(当链表长度到8以后数据结构改为红黑树),是线程不安全,允许key和value为null。底层结构数组叫哈希桶,而桶内则是链表,链表中的节点Node存放着实际的元素。

底层实现了Map<k,v> 的接口并实现了浅拷贝和序列化,HashMap 默认初始值大小为16 ,初始值大小必须为2的幂次,如果用户输入的不是2的幂,那么系统自动更新为输入值附近的2的幂次,最大大小为2的30次幂。HashMap的阈值默认为 0.75,当存储节点超过该值,对map进行扩容。
每次扩容为原来的1倍。

在一次put(添加操作)的时候,HashMap 会先进行初始化,如果没有先进行初始化操作,初始化过程会取比用户指定容量大的最近2的幂次数作为数组的初始容量,如果设置了扩容的阈值也一并更新。初始化完成以后继续put 方法
1.先判断有没有初始化
2.在判断传入的key是否为空 就存储在table(0)位置(及Node首节点,使用CAS来保证添加首节点线程安全)
3.key不为空就对key进行hash,hash的结果在 & 上数组的长度就得到了位置。
4.如果存储位置为空就创建新节点(并使用synchronized锁保证线程安全),不为空就说存在hash冲突了。
5.解决冲突HashMap会遍历整个链表,如果有相同的value值就更新,否则创建节点添加到链表头。
6.添加还要判断存储节点是否达到阈值,达到阈值要进行扩容。
7.扩容两倍,扩容的时候使用Arrays.copy() 进行扩容。
8.扩容过后新插入的节点也要重新进行hash 一遍才能插入。
以上这些是一些常用的知识点,但是如果你只是知道以上这些还是不够的,一般面试官还会问你HashMap 线程安全码? 当然大家都知道是不安全的,但是要是问你怎么解决呢? 如果你要是回答加锁或者回答使用HashTable 基本上就挂了。HashMap是一个线程不安全的容器,在并发操作会出现丢失更新问题,严重会导致cpu宕机的,一般报错为java.util.ConcurrentModificationException.那我们该怎么解决呢?
1.使用java类库提供的collections工具包下的Collections.synchronizedMap(new HashMap()),返回一个线程安全的Map
2.使用并发包(java.util.concurrent)下的ConcurrentHashMap,ConcurrentHashMap采用分段式锁机制实现线程安全。

java8和java7的区别
Hash1.7 和1.8 最大的不同在于1.8 采用了“数组+链表+红黑树”的数据结构,在链表长度超过8 时,把链表转化成红黑树来解决HashMap 因链表变长而查询变慢的问题;
1.7 的底层节点为Entry,1.8 为node ,但是本质一样,都是Map.Entry 的实现
还有就是在存取数据时添加了关于树结构的遍历更新与添加操作,并采用了尾插法来避免环形链表的产生。

 

3.HashMap的长度为什么是2的倍数
在HashMap的操作流程中,首先会对key进行hash算法得到一个索引值,这个索引值就是对应哈希桶数组的索引。为了得到这个索引值必须对扰动后的数跟数组长度进行取余运算。即 hash % n (n为hashmap的长度),又因为&比%运算快。n如果为2的倍数,就可以将%转换为&,结果就是 hash & (n-1)。所以这就解释了为什么HashMap长度是2的倍数。

& 字符串和%字符串 虽然效果一样,但是操作效果更高。

Jdk1.8中满足什么条件后将链表转化成红黑树?

1.putVal方法中是判断桶内的节点个数是否大于8,

2.还要通过treeifyBin方法中判断桶内节点中元素总数红黑树容量64,小於则继续扩容,大於则转为红黑树。

为什么int String 更适合做key?

int 和 String 的好处在于hash 出来的值不会改变。如果是一个对象,那么他们可能会因为内部引用的改变而hashCode 值的改变,会导致存储重复的数据或找不到数据的情况。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章