A:先问两个比较基础的吧,说说八大数据类型吧(先问两个最基本的,试试这货的水准,看看是不是个水货,这个都不知道的话,就直接滚蛋,免得浪费我时间)
B:(这..)
- 浮点型:double、 float
- 字符型:char
- 整型:byte、 short、 int 、long
- Boolean型:boolean
A:那什么是反射呢?
B:en~(果然够基础啊!)
对于任何一个类,都能知道他的属性与方法;对于任意一个对象,都能调用它的方法和属性。
A:嗯,那说说你用到过的集合,并简单阐述一下吧:
B:那我先说说List吧:
- ArryList: 底层采用的是数组,查询快,增删慢。
- LinkList: 底层采用的是链表,查询慢,增删快。
- Vector: 这个知道,底层同样采用的是数组,但是没怎么用过。
A:打断一下,为什么ArryList查询快,增删慢;而LinkList查询慢,增删快呢?(我倒要看看这货是不是又是一位八股文"大佬")
B:
1.那我先说说这两个查询快慢的原因吧,因为Arrylist底层是数组,每次查询的时候我们通过下标进行查询,不需要去进行比较,查询方式是首地址+ (元素长度*下标) ,基于这个位置读取相应的字节就可以了;而LinkList底层是链表,我们每次去查询时,需要一个一个去比对,如果按1s查询一个的话,我们查询n个就需要ns,这样会耗费很长的时间,所以查询慢。
2.接着我再说说两者增删快慢的原因吧,ArryList每次添加或删除数据时,我们如果想要插入数据,那么擦入数据之后的元素就会挨个往后移,删除则与之相反,还有就是如果内存不足的情况下,就需要扩容,这些都会导致增删慢,但是有种特殊情况是,如果你要插入的数据时在首位或者末位,这个时候速度会很快;而LinkedList底层是链表,例如我们现在想要添加一个元素在A和B之间,这两者之间会自动断开,把我们想要插入的数据放到这两个元素之间,删除同样与之相反。
A:嗯,接着往下说。(没想到这货还知道的这么详细)
B: 集合还有个Set:
- HashSet:集合元素可以为空,不可重复,有序。
底层采用的是链表 + 哈希表的算法,链表保证元素的添加顺序,哈希表表保证元
素的唯一性。
- treeSet:有序,不可重复,底层采用的是红黑树算法,擅长于范围性查询。
A:Map有用过么?
B:有的,Map有:
- HashMap:是一个线程不安全的map,方法中没有synchronized(初始大小为16,加载因子 0.75,扩容为1.5倍)
- HashTable:方法中加入了synchronized 关键字,但是现在慢慢被ConcurrentHashMap慢慢 取代了。
- ConcurrentHashMap:jdk1.8之后,采用了CAS和synchronized技术来保证线程安全,底层 采用的是:数组 + 链表 + 红黑树。
A:你刚才有提到那个CAS和synchronized,你能详细说下你对他们的理解吗?
B:
CAS是基于锁的一种操作方式,是乐观锁…
A:那个再打断一下,你提到了锁,你可以详细说明一下吗?
B:
总所周知,我们java中锁分为乐观锁和悲观锁,那我先说一下乐观锁,见名知意我们可以
清楚的知道,当我们在使用它的时候,它会乐观的认为我们不会去修改,就不会加锁,极
大的提高了效率,多用于读比较多的场景;悲观锁,这是一个满满负能量的锁,当我们去使
用它的时候,会认为我们会去修改它,然后就会加锁,性能就会降低,多用于写较多的场
景。
A:可以,那你再接着说说之前的问题。
B:
对了,我刚才说到那里来着了(叫你三番两次的打断我)
A:CAS!(这货在想啥啊,自己说的啥都不记得了)
B:哦哦,不好意思啊
常用的实现方式为:
compare and swap《比较与交换》
实现操作通常是由以下三个数来完成的:
1. M 读取的变量值
2. A 旧的预期值
3. B 新的修改值
更新条件:
当CAS进行修改操作的时候,当且仅当M=A,才会把M修改为B,否则什么都不做,我大 概知道这么多,具体原理需要去了解下CAS实现原理。
A:嗯,那有什么缺点吗?
B:
这个是肯定的是会有的,鱼与熊掌是不可兼得的,因为提搞了性能,所以安全就会得不到保障,就出现了ABA问题。当CAS去修改数据时,M初始值读取的是A,准备修改的时候A=B,确实是满足了条件,但是这个A可能是个多变体,他首先变成了B,接着又变成A,这个时候问题就来了,也就是我上面的说的ABA问题。
A:嗯,那我们怎么去解决这个问题呢?
B:(咋的,这是要"夺命几连"问的节奏啊)
这个嘛,当然是采用Version版本号来解决啦,当A每次变化时,就Version+ 1,这样B读取A的时候,同时把版本号一起读取,这样就算A再怎么变换身份,就会出现版本号不一致。
A:可以,那String、Stringbuilder、Stringbuffer的区别:
B:
- String是字符常量,创建后不可更改;后两者是字符变量,创建后可以更改。
- String和Stringbuilder线程是不安全的,而StringBuffer 线程是安全的
A:嗯,那“==” 与 “equals”的区别呢?
B:
1.“equlas”是超类Object中的方法;“==”是操作符。
2. “==”一般多应用于数值间的比较;“equals”一般多用于对象之间的内存地址的比较。
3. “equlas”的运行速度没有“==”快。
A:上面这些都是些基础知识,接下来我再问问你些关于Redis方面的吧。(看来基础没什么问题了,那我再试试这货Redis掌握的怎么样)
B:好咧(咦,这个变态不知道又会问些什么问题~)
A: 嗯,那你先说说Redis数据类型以及它的使用场景。
B:
1.String(常规计数,例如微博的粉丝数量等),key=>value,value可以是string类型,也可以是数值类型。
2.List(关注列表,粉丝列表)
3.hash(用户信息、商品信息等),key=>value,
4.set(点赞、订阅等)
5.Zset(排行榜、用户列表)
A:那能列举一些你常用的一些命令吗?
B:
- String类型:
Set age 24 赋值
Get age 取值
incr age 自增1
decr age 自减1
mget age age1 获取多个值
- list类型
lpush list1 num从列表list左边插入一个数据;
lpop list1 num 从列表list左边移除一个数据。
Rpush list1 num 从列表list右边插入一个数据;
Rpop list1 num从列表list右边移除一个数据。
llen list1 获取列表list的长度。
- hash类型:
hset name tom 往hash里面添加key-value
hget name 通过key向hash里面获取相应值
hmget name1 name2 通过key从hash里面获取所有Value
- set类型:
sadd set1 num 向set1里添加数据
srem set1 num 从set1里删除元素
scard set1查看set1里面存在的个数
sismember set1 num 从set1查看是否存在某个数据
- Zset:
Zadd student 1 tom 向学生表添加数据
Zrem student tom 从学生表里删除数据
Zrem student tom1 tom2 从学生表里删除多条数据
Zcard tom 查询数据
Zrange student 0 5 score根据学生表里的分数进行排序,排序区间是0,5区间
Zrevrange student 0 5 score 跟上面一样,这里是从大到小进行排序
A:嗯,什么是Redis持久化操作,提供了那两种持久化方式?
B:
Redis持久化就是将缓存中的数据写入到本地磁盘中去,防止数据库宕机从而导致的数据丢失,这两种持久化方式分别是:
- AOF:
1.write:根据条件,将aof_buf中的数据写入到aof文件中去
2.save:根据条件,调用fsync、fdatasync 将aof文件写入到磁盘中去。
- RDB:
1.RDBSave(生成RDB文件)
2.RDBLoad(从文件加载内存)
A:那RDB与AOF的区别呢?
B:区别的话:
- aof频率更新比rdb高,数据还原aof会优先
- RDB的效率优先于AOF
A:那它的储存结构呢?
B:
Redis通讯协议是通过resp的格式命令文本储存的
A:嗯,那再谈谈你对于缓存穿透、缓存击穿、缓存雪崩的理解吧
B:
- 雪崩:
由于原有缓存失效,新缓存又未到,在这期间原本应该请求缓存数据的请求现在直接请求了数据库,造成了数据的压力过大,从而导致了宕机
- 缓存击穿:
原本应该请求缓存中的key,这时候失效了,大批量的请求直接请求了数据库,造成了数据库的压力过大,从而导致了宕机。
- 缓存穿透:
用户要请求的数据,压根数据库就没有,自然缓存中也不会有,用户去缓存中查询数据,找不到对应Key的Value,然后又去数据库进行查询,依然查不到,返回了null,这两次查询都是毫无意义的。
A:说下你之前SpringCloud项目都有用到过那些组件吧
B:
- 注册中心: Eureka
- 动态代理:Feign
- 负载均衡:Ribbon
- 网关:GetWary
A:那你们服务之间的调用采用的是什么?
B:
Feign,通过注解和选择的机器,拼接url路径,来发送请求。