面试题-汇总

2022-02-27  本文已影响0人  liwsh

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语句,同时负责查询缓存的维护。

上一篇下一篇

猜你喜欢

热点阅读