随便分享点不那么常规的面试题(二)

1. 观察者模式和访问者模式有什么区别?

这两种设计模式相对来讲都偏冷门,本题可以回答好的话说明对设计模式有过深刻的了解,在面试偏业务的岗位上有加分mysql

先解释二者概念:面试

  • 观察者模式定义了一种一对多的依赖关系,当某一对象状态改变时,会通知全部观察者
  • 访问者模式定义了一系列访问接口,负责接收具体的数据对象,被访问者经过这些接口将本身的数据交给访问者来处理

再解释二者核心区别和功能不一样点:redis

  • 观察者模式的核心是触发器,主要用于广播通知和动态触发某些行为
  • 访问者模式的核心是解耦,主要用于将数据对象和数据分离,避免让对象上的操做污染对象所在类

最后解释二者优缺点和各自使用场景:算法

  • 观察者模式的优势是能够实现动态触发机制,可是若是存在循环依赖会致使系统崩溃,适用于广播通知/发布订阅/链式触发等场景
  • 访问者模式的优势是契合单一职责原则,同时拥有高度的灵活性,可是具体数据对访问者公布了细节,适用于须要使用数据对象进行不少不一样操做的场景

2. 数据库的页分裂问题讲一下

若是问页分裂问题,通常会在聚簇索引以后紧接着提出,若是没有问,在回答完聚簇索引相关的概念后,要尽可能地给面试官带出页分裂的概念,体现出本身对这一块的熟悉程度sql

数据库索引底层使用B+树来实现,若是插入不规则的数据(指不按key顺序插入),会致使树结构频繁发生较大改变数据库

在数据库中,聚簇索引和非聚簇索引在频繁插入不规律数据时,都会致使严重的页分裂问题。mysql中一页大小为8k,是固定的:设计模式

  • 聚簇索引中,由于索引顺序与物理表顺序一致,因此当插入包含不规律的索引列的数据时,会致使索引树结构发生较大改变,数据页也同时须要分裂,并且会破坏磁盘顺序索引的高效性保证
  • 非聚簇索引中,由于索引是有序的,因此当插入不规律数据时,若是以前的数据页已满,会致使数据页的分裂,同时也会破坏磁盘顺序索引的高效性保证

3. 排序的稳定性意义是什么,若是必定要使用非稳定性排序算法,如何保证稳定性?

本题主要用于考察面试者是否了解排序的概念,而不是仅仅背知识点。第一问不难,基本上知道稳定性的概念就能顺势推出其意义,第二问稍微有点难度,可是只要真正了解稳定性的概念,就能想到一些解决办法缓存

排序的稳定性指拥有相同关键字的记录,在排序后的相对次序保持不变。由于有些数据在排序前的相对顺序是有语义的,非稳定性排序会在排序后丢失这些语义,因此在这种场景下须要保证排序的稳定性bash

当必须使用非稳定性排序算法,且须要保证稳定性时,有两种解决方案:服务器

  1. 剥夺原数据顺序上的语义,好比可使用另外一个数据结构保存语义,或者从业务需求上解决
  2. 若是数据直接拥有在顺序上的语义属性时(好比插入时间/次序等),则重写数据比较器,当关键词相等时,比较数据的顺序属性

4. HashSet是如何实现的?

实现原理很简单,但前提是你主动去了解过

HashSet内部维护了一个HashMap类型的变量,其key值为Set的元素类型,value为Object类型

对全部添加到Set中的元素,HashSet会添加一个元素 => PRESENT的键值对到HashMap中,这个PRESENT是HashSet中定义的一个普通的Object对象。由于HashMap中key相同的元素会相互覆盖,因此保证了集合中没有重复key值的元素存在

5. 事务的ACID特性各自是如何实现的?

ACID的概念很简单,可是想说清原理不容易,其中隔离性和持久性是重点。隔离性的要点是锁机制,有的面试官会紧接着出一些场景题,须要提早准备;持久性的要点是redo logbinlog,有的面试官会引伸到读写分离的数据一致性问题,也须要提早作好准备

A(原子性):原理是undo log,即“撤销日志”。当事务对数据库进行修改时,会生成对应的undo log,若是事务回滚,数据库会使用undo log中的内容将数据修改到以前的状态

C(一致性):经过数据库自己(如外键等)和服务端的代码逻辑层面共同保证

I(隔离性):经过数据库锁机制和MVCC来实现。锁机制保证两个事务的写操做不会相互影响,MVCC保证一个事务的读操做不会被其余事务的写操做影响

D(持久性):原理是redo logbinlog,当数据修改时,会在redo log中记录此次操做(记录的是物理数据,内容基于磁盘page),一般当事务提交时,会调用fsync对redo log进行刷盘(将数据写入磁盘),若是mysql机器宕机,可使用redo log对数据进行恢复。同时binlog做为二进制逻辑日志也能够用户数据恢复

6. strictfp关键词有了解过吗?

若是面试官问你这个问题,惟一的缘由就是他昨天临睡前看到了这个知识点,因此就拿来考你(固然也有多是工做中确实用到)。本题单纯的就是知识扩展,若是不会也不影响

stricpy,即strict float point(精确浮点),只能用来修饰方法或类。被strictpy修饰的方法或类中全部的float/double表达式都严格遵循FP-strict的限制,全部表达式的结果都必须是IEEE-754对操做数预期的结果

strictpy能够消除因硬件不一样而带来的浮点数计算差别,可是并不能避免相似0.05 + 0.01 != 0.06这样的状况,因此在要求高精度浮点计算时,须要使用BigDecimal

7. 看下面这段代码,和fun1相互阻塞的方法有哪几个,为何?

public synchronized static void fun1() {
        try {
            Thread.sleep(2000);
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("[同步-静态方法-1]");
    }

    // -------------------------------------------------

    public synchronized static void fun2() {
        System.out.println("[同步-静态方法-2]");
    }

    public static void fun3() {
        System.out.println("[普通静态方法]");
    }

    public void fun4() {
        System.out.println("[普通方法]");
    }

    public void fun5() {
        synchronized (Demo.class) {
            System.out.println("[类同步-静态方法]");
        }
    }

    public void fun6() {
        synchronized (this) {
            System.out.println("[对象同步-方法]");
        }
    }
复制代码

本题考察点是对synchronized关键字的掌握程度,有些人理论背的很熟,可是随便丢个场景应用就懵了。因此在学一个知识点的时候,最起码本身要动手写几行代码跑一下看看

与fun1相互阻塞的方法是fun2和fun5

fun2是另外一个被synchronized修饰的方法,和fun1同属一类,因此会相互阻塞

fun5中使用了类锁,而synchronized在静态方法上的锁也属于类锁,因此也会相互阻塞

8. 多个客户端要同时修改redis中的一个key怎么办?

通常这种并发修改的场景,均可以用消息中间件来将并行转串行解决,可是面试官一般还想要另外一种答案,因此最少要准备两套方案。本题固然不止我下面列出的这两种方案,只要合理便可

  1. 全部的更新操做所有送入消息中间件中(如kafka/rabbitmq/...)串行化处理
  2. 经过redis的MUTLIWATCH实现:在redis中设置一个key,而后WATCH这个key,经过MUTLI开启事务,而后自增这个key的值,接着再执行真正的修改操做,最后使用EXEC提交事务。经过这种方法,若是发生多线程竞争,因为WATCH机制,监听到key值变化的线程会执行redis操做失败

9. 缓存雪崩、缓存击穿、缓存穿透分别是什么,怎么解决?

本题应该算是偏常规的缓存题,可是有的面试官会把这三个场景放一块儿说来故意迷惑你,因此要注意区分它们之间的不一样点,千万不要死记硬背,不然必定会搞混的

  • 缓存雪崩:指缓存服务器宕机或大量key同时过时,致使大量请求直接打到数据库上,导致数据库服务器宕机。
    • 若是是缓存服务器宕机:部署高可用集群,启用熔断限流机制,以及在启动前使用rdb日志进行数据预热
    • 若是是key批量过时:设置缓存时间时乘上一个随机的负载因子
  • 缓存击穿:某个频繁访问的key过时的瞬间,大量流量直接打到数据库服务器上,致使宕机
    • 能够将热点key设置为永不过时
    • 也可使用双检锁,当在缓存中发现数据不存在时,先获取锁,而后再检查缓存中是否存在数据,若是依然不存在则查询数据库
  • 缓存穿透:用户恶意访问数据库不存在的数据,致使每次查询都会走数据库
    • 若是某次查询没有在数据库中查到数据,则将该key放入缓存中,值设为空,同时设置一个很短的过时时间
    • 限制同一ip短期的频繁访问

10. 为何事务注解不加在Controller层或是Dao层?

本题主要考察对mvc分层的理解程度,只要能把每一层的概念理解了,说个大概仍是没问题的,即便不知道,举几个反例出来就能够了

  • 不加在controller层的缘由:controller的重点是请求逻辑,而不是数据库事务。一般controller会调用多个服务,若是失败只须要一个回滚便可
  • 不加在dao层的缘由:当服务发生异常时,须要总体进行回滚,而加在dao层只能回滚一个操做
相关文章
相关标签/搜索