天天看点

【面经分析】mysql建立索引的几大原则、List,Set,Map、ConcurrentHashMap的实现原理

1、项目的超卖问题如何解决?

首先超卖问题的出现有两个原因,

第一个是一个用户同一时刻发出多次请求,当时库存是够的,然后就出现了一个用户秒杀多件商品;

第二个是数据库底层逻辑没有对库存数量是否>0进行判断,从而导致库存数量减到了负数。

因此解决方法有两个,在后台的秒杀表中,对用户id和商品id设置一个唯一索引,防止一个用户同时秒杀多件商品;

第二就是在sql语句的逻辑中,对库存数量count进行判断是否>0才减库存。

2、排序算法有哪些?

快排、归并、堆、冒泡、选择、希尔、桶、计数排序、基数排序

3、堆排序的过程?

将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;(升序大顶堆,降序小顶堆)

将堆顶元素和末尾元素交换,将最大元素沉到数组末端;

重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

为啥时间复杂度是O(logn),因为交换并重建堆的过程中,需要交换n-1次,重建堆的过程中,是根据完全二叉树的性质逐步递减的,近似为nlogn。

4、Object类有哪些方法?

【面经分析】mysql建立索引的几大原则、List,Set,Map、ConcurrentHashMap的实现原理

5、HashMap的容量为什么要初始化为2的n次幂

计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

先说说哈希表的映射过程,看底层源码可以发现,是hashcode & (length - 1)来达到一个取余的效果,之所以用位运算是因为效率高一些.假如说哈希表的长度是2的n次幂的话,length -1就相当于一个掩码,能够获得hashcode的低位,hashcode的低位实际就是余数.

6、HashMap和ConcurrentHashMap的区别?

参考链接:https://www.cnblogs.com/chengxiao/p/6842045.html

  • 线程安全。HashMap线程不安全,ConcurrentHashMap线程安全;
  • 底层实现。HashMap底层是通过数组+链表+红黑树实现的,concurrentHashMap是通过segment数组采用分段锁策略,实现的。
Segment是一个子哈希表,Segment里维护了一个HashEntry数组,并发环境下对于并发环境下,对于不同Segment的数据进行操作是不用考虑锁竞争的。(就按默认的ConcurrentLeve为16来讲,理论上就允许16个线程并发执行

7、ConcurrentHashMap的实现原理

ConcurrentHashMap内部使用段来表示这些不同的部分,每个段都是一个小的HashTable,他们有自己的锁,只要多个修改操作发生在不同的段上,就可以并发执行。JDK1.8的实现降低锁的粒度,JDK1.7版本锁的粒度是基于Segment的,包含多个HashEntry,而JDK1.8锁的粒度就是HashEntry(首节点)。

【面经分析】mysql建立索引的几大原则、List,Set,Map、ConcurrentHashMap的实现原理

两次哈希的过程,第一次确定segment,第二次定位到元素所在链表的头部。

缺点:

ConcurrentHashMap 是设计为非阻塞的。在更新时会局部锁住某部分数据,但不会把整个表都锁住。同步读取操作则是完全非阻塞的,好处是在保证合理的同步前提下,效率很高,坏处是读取操作不能保证反映最近的更新。

扩容:

在JDK7的时候,采用的是分段锁的机制,ConcurrentHashMap维护了一个Segment数组,Segment这个类继承了重入锁ReentrantLock,并且该类维护了一个HashEntry<K,V>[] table数组。

扩容的实现:先对数组的长度增加一倍,然后遍历原来的旧table数组,将每一个数组元素迁移到新的数组里,迁移完毕后,将新数组的引用直接替换旧的。在迁移链表时,用了两个for循环,第一个for的目的是为了判断是否有迁移位置一样的元素

8、List,Set,Map 三者的区别,使用场景,常见的实现类

区别:

  • list:变长数组,有序,检索效率高,能够根据下标直接获取数据,插入删除效率低。适用于查找操作比较多的情况
  • set:自动去重,检索效率低(因为存储位置是由hashcode决定的,所以存储的对象必须有equals方法,并且没有下标,遍历只能用迭代)
  • map:存储的是k-v键值对,map中不能包含重复的key

常见的实现类:

  • list:ArrayList、LinkedList、Vector
  • Set:HashSet、TreeSet、LinkedHashSet
  • map:HashMap、HashTable、treemap

HashSet:查询速度最快的集合,内部是以hashCode实现的。不保证set的迭代顺序

TreeSet:是二叉树实现的,基于TreeMap,生成一个总是处于排序状态的set,内部以TreeMap来实现,不允许放入null值。

TreeMap:有序散列表,实现SortedMap接口,底层通过红黑树实现。

9、Java注解

  • @Autowired:自动按类型注入,如果有多个匹配按照bean id查找,查找不到会报错;
  • @Qualifier:自动按照类型注入的基础上,按照bean id查找,变量注入时,必须搭配@Autowired,给方法注入时,可用单独使用;
  • @Resource:直接按照bean id注入,只能注入bean类型。
  • @Value:用于注入基本数据类型和String类型。

10、mysql建立索引的几大原则

  • 选择唯一性索引
  • 为经常需要排序、分组和联合操作的字段建立索引(ORDER BY、GROUP BY、DISTINCT和UNION)
  • 为经常需要作为查询条件的字段建立索引
  • 限制索引的数目
  • 尽量使用数据量少的索引
  • 尽量使用前缀来索引
  • 删除不再使用或者很少使用的索引
  • 最左前缀匹配原则
  • 尽量选区分度高的列作为索引
  • 索引列不能参与计算,保持列干净
  • 当单个索引字段查询数据很多,区分度不是很大时需要考虑建立联合索引来提高查询效率

继续阅读