面试题(3.27)
CAS机制
-
什么是CAS机制?
CAS全名是 Compare and Swap的缩写,翻译过来就是比较并替换。目的是为了解决在并发情况下因为线程入侵导致的数据不一致的问题。 如:ThreadPoolExceter中和ArrayList源码中有具体实现。
-
CAS机制是如何实现的?
一个简单的需求 i =0,要进行自加的操作。
执行一个方法
- 记录int b = i
- 执行逻辑
- b != i(由于在多线程的环境下i可能是会发生变化的,i是从内存中直接取出的)
- 如果等于true i自加操作失败,进行自旋操作
- 如果等于false 说明在执行逻辑中没有其他线程修改我们的i值,所以自加成功。
-
CAS是一个乐观锁
从思想上来说,synchronized属于悲观锁,悲观的认为程序中的并发情况严重,所以严防死守,CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去重试更新。
-
普通CAS机制存在ABA问题?
当一个值从A变成B,又更新回A,普通CAS机制会误判通过检测。
利用版本号比较可以有效解决ABA问题。
ArrayList
ArrayList的Iterator中采用的CAS机制
CopyOnWriteArrayList的Iterator中是Copy的方式.
ArrayList vs LinkedList
HashMap
单例模式
饿汉式
- 私有构造
- new一个private static final 对象
- pulic static 对象 getInstance 方法 获取步骤二的对象
枚举饿汉式
懒汉式
DCL懒汉式
volatile的意义:
由于CPU为了提高效率会对编译后的命令进行重排序操作,但是重排序后会导致给static共享对象赋值的时候并没有进行调用构造方法,此时如果其他线程入侵就会导致得到一个并未完全调用构造方法的对象(对象成员变量不完整),然而加volatile可以避免重排序,为了保证安全而降低了部分cpu的性能.
正常排序:
重排序后:
懒汉式(内部类)
static代码块 通过JVM保证线程安全
Redis
Redis 是单线程还是多线程?
6.0之前Redis采用的是单线程网络IO请求,单线程数据读写。6.0之后Redis采用的是多线程去实现网络IO(,但是数据读写还是单线程的。
Redis速度为什么这么快?
- 命令执行是基于内存操作
- 读写是通过单线程减少了线程上下文的切换
- 基于IO多路复用机制,提升Redis的效率
- 高效的数据结构,跳跃表,压缩列表,链表等。
Redis底层数据结构是如何利用跳跃表来存储的?
存储zset进行排序本来是基于有序链表,但是查找慢,所以将有序链表改造成为了跳跃表,类似于“折半查找”,可以进行快速的增删改查。
Redis的删除策略
- 惰性删除:当一个key到达了过期时间不会被马上删除,而是在下次调用的时候去判断这个key是否过期,如果过期了,就会去删除。
- 定时删除:惰性删除并不能删除冷数据,定时删除默认(100ms)删除一小部分过期的key,并不是全部过期的key,所以key已经过期了并没有被删除。
Redis的内存淘汰策略
Redis主从,哨兵,集群
主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
Redis集群模式是如何分片的?
Redis持久化 RDB AOF和混合持久化
线上Redis持久化策略如何设置?
Redis中的缓存穿透,缓存击穿,缓存雪崩
如何解决Redis和数据库数据不一致问题?
延时双删 先更新数据库在删缓存,发送消息到MQ延时一到二秒,再删一次缓存。
可以通过延时双删或者cannal监听进行实现
Redis分布式锁的问题
RabbitMQ
RabbitMq如何保证消息的可靠性?
-
消息确认机制
-
消息持久化
DB