美文网首页
面试题-汇总

面试题-汇总

作者: liwsh | 来源:发表于2022-02-27 23:37 被阅读0次

    1.Redis面试题

    1.说说你项目中redis的应用场景

    说一个redis的应用场景,业务埋点

    2.redis是单线程还是多线程

    无论什么版本,工作线程是一个。6.X高版本出现了IO多线程。IO多线程依赖epoll进行多线程读取和输出,更多压榨服务器性能

    3.说说pipeline,lua脚本,事务

    redis命令都是原子执行的,pipeline是客户积攒了一堆命令,发送到服务端,但是这些命令不会一起执行。redis事务是开启事务,然后命令都缓存到服务器队列,客户端发送执行命令的时候,队列的所有命令依次执行,如果有失败跳过,执行下一个redis命令。lua脚本是原子的

    4.缓存穿透,击穿,雪崩

    穿透:数据不存在请求打到数据库,只让一个请求到数据库,查询不到数据redis塞一个空,或者直接布隆过滤器过滤(布隆过滤器说不存在,肯定是不存在)。
    击穿:如果预知哪些是热点数据,可以value里面带一个时间,比过期时间短。取到数据发现快要过期了,一个线程加锁去取数据,其他线程返回旧数据。如果不能预知哪些是热点数据,一个之前没有缓存的数据,突然大量请求。加锁一个线程取数据,其他线程之间返回。
    总之:保证数据库不被打垮,只让有效请求进入数据库。加锁只让一个有效请求进入数据库,其他请求等待,如果是恶意请求,需要布隆过滤器,或者缓存空

    5. redis如何删除过期key

    1.后台轮询,分段分批删除过期key
    2.请求的时候判断已经过期了

    6. 缓存是如何淘汰的

    lru/lfu/random/ttl

    7.如何进行缓存的预热

    提前将数据缓存到redis,如果有一些没有缓存成功,加锁让一个请求去获取数据,其他线程等待

    8. 缓存和数据库不一致

    先操作数据库,然后删除缓存。 如果删除了缓存,然后另外一个操作读取到了旧数据会导致数据不一致(另外一个操作可能更新数据库前就读取了数据库,然后删除缓存后才更新缓存)。这里延迟删除一下缓存就好了。 (消费binlog强制保证缓存删除成功)

    9 redis主从不一致

    redis是弱一致,异步保持数据同步。 锁不能用主从(单实例,分片集群,redlock=》redisson)

    10.redis持久化原理

    RDB,AOF。 不要用作存储

    11. 最佳实践

    1.不要有大value,会导致redis单线程阻塞,拆分到多个分片上(规则用户规则缓存是一个大key)
    2.规避大数据量操作smembers,hgetall
    3.避免出现热点key,提前进行拆分或者每个分片冗余,比如库存。

    12. redis分布式锁

    存在的问题:1.超时释放锁,活还没干完。2.redis主挂了,锁丢了。3.释放了别人的锁。4.没法实现阻塞和公平锁。但是redis性能高,如果用zk,锁是靠新建和删除临时节点实现,只有leader可以干,性能弱但是安全。

    13. sorted set数据结构

    image.png

    14.redis做延时队列

    sortedSet 用时间戳做score,消息内容为key。 zadd添加消息,zrangebyscore获取n秒前的数据。

    2. JVM

    2.1 描述一下jvm内存模型

    a. 服务启动的时候类加载器将class加载到方法区(持久代),持久代参数必需设置,如果不设置持久代扩容会导致full gc。持久代初始值和最大值设置一样即可。类加载相关内容参考:https://www.jianshu.com/p/6f18ac304255
    b. 服务启动时创建的各种实例在jvm的堆中,实例的回收靠垃圾回收器,这里有cms,g1,zgc。垃圾收集器参考:https://www.jianshu.com/p/346eb6a77da5
    c. 程序运行的时候是用的虚拟机栈,如果要调本地方法会用到本地方法栈,程序计数器指向正在执行的指令。

    2.2 堆内存划分的空间,如何回收这些对象

    cms和g1都分新生代和老年代,新生代eden和2个survivor区。g1主要是可以控制gc时间。具体参考垃圾收集器的文章

    2.3 如何解决线上频繁gc问题

    线上频繁full gc,主要是晋升太多对象到老年的(规则的一个本地缓存每次都全量刷新,导致老年的增长过快),或者老年的对象泄漏了回收不了(曾遇到过打印的日志拼接在一个静态的属性上导致内存泄漏)

    2.4 常见gc问题

    1. young gc尖刺,因为写日志遇到磁盘繁忙
    2. young gc耗时缓慢增加,String.intern字符串常量池过大因为常量池是hashtable维护的,常量池数据过多hash冲突严重,查找就比较耗时。
    3. old-gen scanning时间过长,调整-XX:ParGCCardsPerStrideChunk=4096 参数

    2.5 内存溢出的原因,如何排查

    outOfMemoryError:java heap space:java堆溢出,代码问题的可能性比较大
    outOfMemoryError:direct buffer memory:直接内存不足,框架的byteBuffer分配了内存没有回收。
    stackOverFlowError: 栈溢出

    2.6 happens-before规则

    程序顺序规则,锁规则,volatile变量规则,传递性,线程启动规则终止规则,线程中断规则。

    3. 多线程-面试题

    1. 如何预防死锁

    按顺序加锁,批量上锁,获取不到锁不阻塞,超时等待。

    2.线程几种创建方式

    runnable
    callable
    继承thread
    futureTask

    3.java wait和sleep的区别

    wait是释放锁,这个锁是打标在对象头,所以属于object方法。sleep是thread的方法,因为是线程本身休眠,不释放锁。线程都会阻塞

    4.进程和线程的区别

    进程是系统资源分配的最小单位,线程是cpu调度的最小单位。 如果linux fork进程不同享内存,那是另外一个进程。如果调用clone创建一个进程共享同一片内存,那叫做线程。知识换了一个名字

    5.java线程生命周期

    阻塞,运行,销毁。 新建,new一个线程,还未绑定操作系统的线程。 调用start后属于就绪状态,已绑定操作线程,等待cpu调度。阻塞(等待sync锁),等待(wait,sleep,await)

    6.描述notify 和notifyAll的区别

    锁池和等待池。 调wait进入等待池,调用notify唤醒一个进入锁池,调用notifyAll唤醒所有的进入锁池。

    7.描述synchronize和lock区别

    由于sync性能差,所以有lock。 sync只有一个等待队列,没有多个等待队列。 lock是java自己实现的比较灵活,比如获取锁,和等待队列。

    8.并发和并行

    并行:多个任务同时在多个cpu运行
    并发:多个任务在一个cpu运行,运行很快看起来是一起发生

    9.ABA问题

    做了某一件事情,然后又恢复了,别人不知道做了这件事情。比如+1后又-1。解决方案:递增版本号

    10.实现一下DCL

    先判空,如果为空加sync锁,然后再判空,如果为空初始化对象。加锁的时候,有线程进入了竞争队列,抢到锁之后需要判空

    11 lock condition原理

    image.png

    12 多个线程顺序打印ABC

    A线程打印A,通知B,B线程打印B通知C,C打印C。

    13 volitale,atomic,lock分别解决什么问题

    volitale解决可见性,atomic cas解决原子性,lock解决原子性

    14 线程池运行原理

    image.png

    15 synchronize原理

    image.png

    4. java基础-面试题

    面试注意点:
    熟悉的多聊(3-5分钟),不熟悉的少聊。一个问题一个问题的环环嵌套,层层递进,由浅入深。慢慢由自己主导面试,引导面试官问你熟悉的领域。
    答题思路:总,分,总。 点,线,面

    1 请聊一下java的集合类

    简单介绍,arrayList,LinkedList,hashSet,hashMap,concurrentHashmap。

    2 hashmap为什么要使用红黑树红

    jdk1.8 链表大于8变成红黑树,加快检索速度。红黑树本身是一颗二叉树,保证树平衡,从而保证操作比较快。

    3 集合类如何解决线程安全

    ConcurrentHashMap实现方式,底层具体实现,synchronized+cas保证线程安全
    size方法规避伪共享,变量abc共享一个缓存行,任何一个变量修改,会导致abc三个变量缓存都失效叫做伪共享。
    ConcurrentSkipListMap 线程安全的有序hash表(相当于安全的treeMap),通过跳表实现的
    copyOnWriteArrayList适合写少读多,写的时候负责一个新容器,只保证最终一致性

    4 简述自定义异常场景

    检查异常统一处理

    5 描述object常用方法

    toString:对象的字符串表示形式
    clone:返回一个对象的副本,深克隆,浅克隆,原型模式
    finalized:GC会调用这个方法,可以使用这个方法自救

    6 1.8新特性

    lambda表达式
    函数式接口
    stream api
    新时间日期api
    接口默认方法,静态方法

    7 继承,封装,多态

    8 java重写和重载

    9 java自增是线程安全吗,如何实现线程安全的自增

    10 jdk1.8的stream用过吗,stream并行原理

    fork/join里面默认线程池

    11 forkjoin框架,适用场景

    将大任务拆分成各个小任务。fork:分拆,join:合并

    12 java 中代理有几种模式

    静态代理
    动态代理
    jdk-proxy: 面向接口的动态代理,代理一个对象去增强面向某一个接口中定义的方法。缺点:没有接口不可用,只能读取接口上的注解
    cglib:面向父类的动态代理,可以读取到类上的注解
    AOP:借助proxy和cglib使用

    13 equal和hashcode方法要同步重写

    equal相等,hashcode一定要相等

    14 hashMap在1.8做了哪些优化

    1.红黑树
    2.链表插入节点方式:1.7头部插入,1.8尾部插入
    3.hash函数:将hash值高位16位也参与hash计算,降低冲突概率
    4.扩容优化,rehash1.8不需要重写进行位置计算

    15hashMap为什么是扩容2倍

    1.8 扩容之后,方便位置计算。其二,降低冲突概率

    16 解决hash冲突的办法

    开放定址法,再hash法,链地址法

    17hashmap为什么使用红黑树,为什么不用avl树

    18 tomcat 为什么要重写类加载器

    先讲双亲委派机制,目的:实现隔离(一个web容器部署多个应用,webAppClassLoader),无法实现热替换,jsp修改动态生效(jasperLoader,jsp文件有修改,废弃jsp文件对应的load,重新new一个)。

    19 java反射影响性能吗

    大量影响性能,大量本身说明编程思想有问题

    20单例模式

    饿汉模式
    懒汉式模式
    静态内部类
    枚举模式

    5.网络IO

    1.网络连接流程
    服务端bind+listen,客户端经过三次握手,建立起一个连接。服务端通过accept拿到连接,如何通过accept拿连接呢,这就是io模型。boi服务端阻塞等待,nio服务端立刻返回,等待内核回调。
    2.tcp为什么是3次握手
    证明双发的收发能力,客户端fin,证明自己🈶发送能力。 fin+ack,证明服务端有发送+接收能力,ack证明客户端有接收能力

    1. tcp为什么是4次挥手
      服务端收到客户端断开连接,还有事情要处理。客户端fin标识要断开连接,服务端fin+ack表明收到请求,进入close_wait状态(如果很多,说明服务端忘记close)。服务端处理事情完毕后,fin客户端收到后回复ack进入time-wait状态维持2msl(保证延迟的网络包都消失和服务端如果没有收到ack,会重复fin,但是客户端关闭了,服务端会报错)
    2. 长连接和短连接
      长连接:复用tcp连接,缺点:占用服务器资源,如果客户端是固定的,而且访问很频繁,长连接合适
      短连接:每次都需要建立连接,服务器消耗资源少。如果客户端体量很大,一段时间是这一波用户,一段时间是另外一拨用户,短连接合适。
      考核指标,连接建立起来,如果复用很频繁,就长连接,反之短连接。
    3. epoll poll select区别
      6.io模型
      io分2步:1.等待网卡数据,2.数据内核拷贝到用户区
      BIO 同步阻塞,1,2步都阻塞
      NIO 同步等待,1不阻塞(epoll),2阻塞
      AIO 异步不阻塞
      7.netty特点
      传输快,零拷贝
      高并发:依赖nio
      核心组件:
      a. buffer: 与channel进行交互,数据是从channel读入缓冲区,从缓冲区写入channel中
      b. flip方法:反转缓冲区,将position给limit,然后position置为0,切换读写模式
      c. clear方法:清除此缓冲区,将position置为0,吧capacity的值给limit。
      d. directByteBuffer:减少系统空间到用户空间的拷贝,但buffer的创建和销毁成本更高,不可控,通常使用内存池来管理。如果数据量小,中小应用可以考虑heapBuffer,jvm来管理。
      f.channel:IO源与目标打开的连接,是双向的,但不能直接访问数据,通过buffer交互
      g. selector: 一个单独的线程管理多个channel,open方法可创建selector,register方法向多路复用器注册通道,可监听事件类型:读,写,连接,accept。
      h. nio建立连接的过程:Selector.open打开一个selector,ServerSocketChannel.open()创建服务channel;bind():绑定到某一个端口。register()注册channel和关注事件到selector上; select轮询拿到已就绪事件。
      i. tcp粘包,拆包原因和解决办法
      tcp以流的方式处理数据,一个完整的保会被tcp拆分成多个包进行分发,也可能把消毒封装成一个大的数据包发送。要发的数据大于包的容量发生拆包,小于的话发生粘包现象。
      j.了解哪几种序列号协议
      关键因素:序列号后大小,序列号对cpu占用,是否支持跨语言
      java默认序列化:无法跨语言,序列化后大,消耗cpu
      json:消耗cpu,跨语言,序列化后数据小。适合传输数据量少,实时性要求低的系统
      thrift:序列化体积小,速度快,支持多语言。不适合数据持久化序列化协议,适合rpc调用
      hessian 二进制协议轻量级工具
      k. reactor模型

    6.mybatis

    1 mybatis编程步骤

    sqlSessionFactory创建sqlSession,通过sqlSession执行数据库操作,调用session.commit提交事务,close关闭会话

    2.mybatis工作原理

    读取mybatis配置文件,配置mybatis运行环境比如数据库连接信息。加载sql映射文件,文件配置了操作数据库的sql语句。构造会话工厂,通过环境配置信息构建sqlSessionFactory。创建会话对象sqlSession。Executor执行器,它根据sqlSession传递的参数动态生成要执行的sql语句,同时负责查询缓存的维护。

    相关文章

      网友评论

          本文标题:面试题-汇总

          本文链接:https://www.haomeiwen.com/subject/eoaflrtx.html