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.png14.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问题
- young gc尖刺,因为写日志遇到磁盘繁忙
- young gc耗时缓慢增加,String.intern字符串常量池过大因为常量池是hashtable维护的,常量池数据过多hash冲突严重,查找就比较耗时。
- 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.png12 多个线程顺序打印ABC
A线程打印A,通知B,B线程打印B通知C,C打印C。
13 volitale,atomic,lock分别解决什么问题
volitale解决可见性,atomic cas解决原子性,lock解决原子性
14 线程池运行原理
image.png15 synchronize原理
image.png4. 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证明客户端有接收能力
- tcp为什么是4次挥手
服务端收到客户端断开连接,还有事情要处理。客户端fin标识要断开连接,服务端fin+ack表明收到请求,进入close_wait状态(如果很多,说明服务端忘记close)。服务端处理事情完毕后,fin客户端收到后回复ack进入time-wait状态维持2msl(保证延迟的网络包都消失和服务端如果没有收到ack,会重复fin,但是客户端关闭了,服务端会报错) - 长连接和短连接
长连接:复用tcp连接,缺点:占用服务器资源,如果客户端是固定的,而且访问很频繁,长连接合适
短连接:每次都需要建立连接,服务器消耗资源少。如果客户端体量很大,一段时间是这一波用户,一段时间是另外一拨用户,短连接合适。
考核指标,连接建立起来,如果复用很频繁,就长连接,反之短连接。 - 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语句,同时负责查询缓存的维护。
网友评论