2021/01/28背题笔记
昨天在准备一家面试,就在复习,没有刷牛客的讨论贴里的问题
Java基础
-
JAVA 中的几种数据类型是什么,各自占用多少字节。
boolean-只占一bit,1/8byte,byte-1,short,char-2,int,float-4,long,double-8
-
String 类能被继承吗,为什么。
-
两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
否,hashmap中,hashCode只是定位到数组位置,还有链表里顺序一一比较的过程
-
String 属于基础的数据类型吗?
属于对象
-
Java 中操作字符串都有哪些类?它们之间有什么区别?
String,StringBuffer,StringBuilder,底层都是用char数组保存,String的增删改查实际是创建新对象,StringBuffer,StringBuilder都是在原对象上进行修改,其中StringBuffer由于使用了syn是线程安全的
-
Java 中 IO 流分为几种?
BIO,NIO,AIO,IO多路复用
-
BIO、NIO、AIO 有什么区别?
BIO阻塞IO,当向kernel发数据的时候,如果没有拿到数据,kernel会阻塞住请求直到拿到数据,
NIO非阻塞IO,kernel数据没有准备好会返回给error,而不是先阻塞住,这样用户会不断发送请求,
AIO异步IO,用户发起请求后,就可以等着了,kernel会立刻返回不会阻塞,然后kernel会把数据拷贝到用户内存,完毕后会通知用户
IO多路复用,select无差别轮询O(n),poll和select类似但是没有最大连接数限制O(n),epoll事件驱动O(1)
-
用过哪些 Map 类,都有什么区别,HashMap 时线程安全的吗,并发下使用的 Map 是什么,他们的内部原理分别是什么,比如存储方法,hashcode,扩容,默认容量等。
hashtable,hashmap,TreeMap,LinkedHashMap,concurrentHashMap,
hashtable不允许键值为null,线程安全,每个方法都加了synchornized,默认容量11,扩容翻倍+1
hashmap,允许null存在,线程不安全,默认容量16,扩容翻倍
TreeMap,默认按键值升序排序,无容量限制
LinkedHashMap,默认插入顺序,iterator遍历时,先访问的是先插入的,和hashmap一样
并发使用concurrenthashmap,扩容和hashmap一样
-
如何将字符串反转?
StringBuilder,StringBuffer的reverse,
-
抽象类必须要有抽象方法吗?
不必要,但是如果有抽象方法必须是抽象类
-
普通类和抽象类有哪些区别?
抽象类由abstract修饰,不能被实例化,不能被final,private,static修饰,子类必须实现抽象类方法,或者继续作为抽象类
-
抽象类能使用 final 修饰吗?
不能,因为他需要被继承,要把自己的内容公开给子类
-
ArrayList 和 LinkedList 有什么区别?
数组实现和链表实现,arraylist初始容量10,扩容为1.5倍
随机访问Arraylist快可以根据数组下标直接访问,但是扩容和删除元素慢
-
ConcurrentHashMap的数据结构(必考)
类似于hashmap的底层数据结构,,Entry数组中的value和next都被volatile修饰,来保证cas时线程间的可见性,1.7采用segment分段锁,计算三次返回size大小,1.8采用node数组+红黑树+cas+syn,使用volatile修饰的basecount来记录元素个数,cas+syn不仅解决了分段所浪费空间的问题,而且效率不相上下,但是chm是弱一致性的,因为在遍历过程中返回的数据可能被并发修改,比如寻找最大元素,在遍历的过程中,可能插入了一个更大的元素,所以他也不能取代强一致性的hashtable,可以使用Collections.synchronizeMap,类似于hashtable,但是接收任何map的传入,
扩容过程transfer,分为单线程扩容和多线程扩容,如果是单线程和hashmap一样,构建一个nextTable,数据迁移,然后让nextTable称为新的table,如果是多线程扩容,或利用forword,如果一个节点非空且不是forword,加锁,处理完把对应值设置为forword,如果是forword直接跳过
-
volatile作用(必考)
可见性和防止指令重排(内存屏障)
-
Atomic类如何保证原子性(CAS操作)(必考)
底层依赖于unsafe类,里面用的都是native代码,很屌,unsafe底层用的是cas,cas也有缺点一是只能操作一个共享变量,多个的时候只能用锁,二是aba问题(时间戳)
-
为什么要使用线程池(必考)
频繁的线程创立和销毁浪费系统资源,为了增强复用性,线程池维护一部分活跃的线程,来提高系统效率
Redis
-
Redis的应用场景
-
热点数据缓存
-
限时任务expire
-
排行榜zset
-
锁?setnx
-
队列?
-
-
Redis支持的数据类型(必考)
-
string hash list set zset
-
-
zset跳表的数据结构(必考)
-
最底层为一个链表,以抛硬币的形式进行数据节点上浮,,每一个节点最多只有向右和向下的指针
-
-
Redis的数据过期策略(必考)
-
定时删除(让定时器在键过期的时间达到时删除)-对内存友好,对cpu不友好
-
定期删除(每隔一段时间对数据库进行一次检查)-折中,但是很难把握这个频率
-
惰性删除(过期也放任不管,但是每次拿的时候判断,如果过期就删除,没过期就返回该键)-对cpu友好,对内存不友好
-
-
Redis的LRU过期策略的具体实现
-
并非按照常规的双向链表+HashMap,而是采取类似与LRU的一种做法(用来节省next,pre指针的空间):--随机取出若干个key,然后按照访问时间排序,淘汰掉最不常用的,具体使用了一个全局的LRU时钟,server.lruclock
-
-
如何解决Redis缓存雪崩,缓存穿透问题
-
缓存击穿:mutex,设置缓存永不过期(后台异步更新,虽然会出现有部分连接访问到旧数据的情况)
-
缓存穿透;互斥锁mutex(就是在缓存失效的时候,不是立即去loaddb,而是先使用缓存工具的某些成功操作返回值,去set mutexkey,再进行load db操作回设缓存),,布隆过滤器,或者直接异步更新讲这次返回为空的数据请求缓存(不太好)
-
缓存雪崩:相当于多个缓存击穿同时发生,或者服务器刚启动的时候(解决办法,预热缓存,再系统启动之前用),并发量不多时,最多解决方法是加锁排队--分开存放热点数据,且错时过期
-
-
Redis的持久化机制(必考)
-
rdb:快照形式保存,bgsave(相对于save不会阻塞)fork一个子进程创建RDB文件,载入RDB文件时时会阻塞(过期key不会载入),恢复大量数据的时候速度比AOF快,缺点保存过程较慢,如果发生意外数据全丢了
-
aof:增量存储,追加命令,而非修改数据,相比rdb快照形式,aof存储粒度更小,但是由于多次修改会产生很多命令,所以aof文件很大,注意如果都开,默认aof载入
-
采取rdb+aof混合使用,redis4.0开始支持,把rdb以命令的形式写入aof中,再以aof形式写入文件
-
-
Redis为什么是单线程的?
官方答案 因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
-
什么是缓存穿透?怎么解决?
数据即不再缓存也不再数据库,多为黑客恶意访问,布隆过滤器
-
Redis持久化有几种方式?
RDB,AOF
-
Redis为什么这么快?(必考)
单线程,内存,IO多路复用
-
Redis怎么实现分布式锁?
对一个变量,使用setnx锁,如果加锁成功为1,加锁不成功返回0
-
Redis如何做内存优化?
-
共享对象池,内部维护[0-9999]证书对象池
-
缩减键值对象,满足业务要求下key越短越好,value适当压缩(讲对象序列化为二进制数组放入Redis)
-
尽可能使用hash
-
编码优化,字符串优化
-
控制key数量
-
-
Redis数据淘汰策略有哪些?6
random(allkey,volatile),lru(volatile,allkey),ttl-volatile,no-evction
-
Redis常见的性能问题有哪些?该如何解决?
-
save阻塞?master最好不要内存快照,用bgsave
-
aof过大时,master重启恢复速度极慢,master不要做任何持久化工作,尤其不要rdb,可以salve开启aof备份数据,策略每秒同步一次
-
master调用bgrewriteaof重写aof,容易挤满性能
-
为了速度和连接稳定性,主从复制最好在同一个局域网内
-
-
Redis的使用要注意什么?
-
并发竞争key的问题,可以用redis事务机制,也可以先准备一个分布式锁,谁抢到谁来
还有一部分其他技术点的,明天在补上

浙公网安备 33010602011771号