经常问的14000
1线程的sleep() 和 wait() 区别
sleep是Thread类的方法,wait是Object类中的方法 sleep可以在任何地方使用,wait只能在synchronized方法或块中使用 sleep让出CPU,让线程睡眠一段时间,不释放线程资源,wait让出cpu,释放已占有资源,直到超时或被唤醒
最大线程数目
最大线程数目 = 核心线程+救急线程的最大数目
Callable(有返回值可以抛异常) 和 Runnable的区别
Runnable和Callable功能是一样的,都是构建线程 ·
Runnable没有返回值
线程安全和线程不安全的理解
在多线程环境下,共享数据或资源可能因并发访问导致数据错乱、逻辑异常等现象
常见的线程安全的类String、HashTable、StringBuffer、java.util.concurrent包下的类
过滤器和拦截器的区别?
1过滤器常用于参数校验基于回调和Servlet 容器, 不能访问Controller上下文, 只能在容器初始化时被调用一次
2拦截器常用于权限检查、日志记录基于反射,可以访问Controller上下文,只能对Controller请求起作用,可以多次被调用
在网关用过滤器判断有没有登录,没有useid为0,有useid登录,
用threadlocal把userId放入请求头中。在微服务中就可以从请求头获取userId
使用拦截器,把userId放入线程的副本TheadLocal。拦截请求,获取头中的userId 注册拦截器 implements WebMvcConfigurer
在业务中直接从Threadlocal中获取userId
线程池有7大参数:
然后当时我们的核心线程数是10,然后最大线程是100,阻塞队列是500,非核心线程生存时间是10秒,拒绝策略是让调用者执行任务
线程池的拒绝策略有哪些?
线程池的拒绝策略主要有以下四种:
-
Abort默认拒绝策略会抛出异常。
-
Caller 被拒绝的任务会由调用的线程直接执行。可以避免创建新的线程
-
DiscardPolicy 不抛出任何异常,不会对程序造成影响,但会丢失处理任务的机会。
-
DiscardOldestPolicy 会丢弃队列中最旧的未处理任务,重新提交被拒绝的任务
避免最新的任务被丢弃,但可能会导致一些老任务得不到处理。
这些策略可以通过ExecutorService 接口的系列ThreadPoolExecutor 类的构造函数指定
说下一个线程的状态生命周期。
新建、就绪、运行 、阻塞和死亡。 这五种状态都可以通过 Thread 类中的方法进行控制。
① 新建状态:使用 new 操作
② 就 绪状态:使用 start()就绪状态
③ 运行状态:系统真正执行线程的 run()方法。
④ 阻塞和唤醒线程阻塞状态:使用 sleep(),wait()方法进行操作。
⑤ 死亡状态:线程 执行了 interrupt()或 stop()方法
题目 11:线程池状态有哪些?
运行状态
整理状态
关闭状态
停止状态
销毁状态
Java 中用到的线程调度算法是什么?
抢占式。一个线程用完 CPU 之后,操作系统会根据线程总的优先级分配给某个线程的下一个时间片
submit 和 execute 方法的区别?
1、submit 和 execute的参数都可以是 Runnable,submit 也可以是 Callable
2、submit 有返回值且方便 Exception 处理,而 execute 没有返回值
Java 中有哪些锁?
使用线程安全类,如:java.util.concurrent包下的类
使用sychronized关键字
使用并发包下Lock相关锁
lock 的存储结构:一个 int 类型状态值(用于锁的状态变更),一个双向链表(用于存储等待中的线程)
线程安全,只需要代码满足原子性、可见性、有序性即可。
-
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作
-
可见性:一个线程对主内存的修改可以及时地被其他线程看到
-
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序
乐观锁、悲观锁的区别
乐观锁如CAS操作操作收据的时候很乐观,认为别人不会修改数据, 只有执行更新的时候才会判断有没有占用, 适用于多读的应用 类型
如果多个线程调用add()方法,会有线程安全问题: CAS和volatile配合使用可以实现无锁并发
悲观锁操作数据的时候很悲观,认为别人一定会修改数据,操作数据的时候直接上锁,都觉得不安全线程 操作完成释放锁关键字 synchronized、接口 ReentrantLock 行锁 乐观锁适合读大于写的场景,悲观锁适合写大于读的场景
synchronized 和 volatile 的区别是什么
• synchronized: 可修饰变量、方法和代码块,具有原子性,有序性和可见性; 禁止指令重排。
• volatile:只能修饰变量,不具有原子性 ,不能禁止指令重排,却保证 了有序性,volatile 能保证数据的可见性,不能用来同步,因为多个线程并发访问 volatile 修饰的变量不会阻塞。
volatile不能保证线程安全而synchronized可以保证线程安全
synchronized 和 lock 的区别
synchronized 可用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用在代码块上。
synchronized 会自动加锁和释放锁,Lock 需要用 lock.lock() 手动加锁和lock.unlock()手动解锁,
ReetrantLock 和 ReadWriteLock。
Lock 呢底层其实是 CAS 乐观锁 ,Syncronized 底层是悲观锁, 资源竞争不激烈Synchronized 的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized 的 性能会下降几十倍 ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。
MyBatis 缓存?
一级缓存: 基于HashMap 本地缓存,其存储作用域为 Session,
当 Session close 之后,该 Session 中的所有缓存就将清空,默认打开
一级缓存。
• 二级缓存 存储作用域为 Mapper,并且可自定义存储
默认不打开二级缓存
需要实现 Serializable 序列化接口打开二级缓存
MyBatis 动态 SQL 了解吗?
\1. MyBatis 动态 SQL 可以让我们在 XML 映射文件内,以标签的形式编写动态
SQL,完成逻辑判断和动态拼接 SQL 的功能;
if为空 and
choose or
where
set
foreach
trim
bind
什么是索引
(什么是索引?索引原理)索引是单独的, 数据库表中一列或多列的值进行排序的,可以让程序能够快速找到所需内容。
SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;
需要额外开辟空间和数据维护工作。
-
索引是物理数据页存储,在数据文件中(InnoDB,ibd文件),利用数据页(page)存储。
-
索引可以加快检索速度,但是同时也会降低增删改操作速度,索引维护需要代价。
索引的类型?
•从数据结构 1B+树 树索引 2Hash
物理存储 聚集索引 非聚集索引
逻辑角度 1. 普通索引 2. 唯一索引 3. 主键索引 4. 联合索引
-
唯一索引:保证索引列的值唯一,不允许重复。
-
联合索引:在多个字段上创建的索引。
MySQL事务是由存储引擎实现的
MySQL 默认是 Innodb 存储引擎,适合比较庞大的应用场景
Innodb 是事务安全的存储引擎,它具备提交、回滚以及崩溃恢复的功能以保护用户数据。
支持外键约束 是行级别锁 性能好适用于多用户并发数
InnoDB使用的索引的数据结构是B+树,
MyISAM:MyISAM 既不支持事务、也不支持外键、其优势是访问速度快,但是表锁定限制其应用于只读或者以读为主的数据场景。
Memory:在内存中存储所有数据,应用于对非关键数据快速查找的场景。Memory类型的表因为存放在内存访问数据非常快,一旦服务关闭,表中的数据就会丢失
主键索引非主键索引
主键索引保存的都是整行的数据内容, 会直接返回主键索引对应的整行数据
而非主键索引则保存的都是所在行的行id。
数据库ACID
事务原子性、一致性、隔离性和持久性
事务是用户定义的一个操作序列,这些操作序列是一个不可分割的工作单位。
原子性- 业务要么全部成功,要么全部失败。
一致性,事务执行失败,所有被该事务影响的数据都恢复到事务执行前的状态,也称为事务回滚。
隔离性,在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
持久性,表示事务完成之后,对系统的影响是永久性的。如果已提交的数据在事务执行失败时,数据的状态都应该正确。
数据库三大范式原⼦性唯⼀性直接性
原⼦性,列或者字段不能再分
唯⼀性,⼀张表只说⼀件事,
直接性,数据不能存在传递关系,即每个属性都跟主键有直接
关系, ⽽不是间接关系。
说一下 MySQL 的行锁和表锁?
MyISAM 只支持表锁,
InnoDB 支持表锁和行锁,默认为行锁。
• 表锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
• 行锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。
题目 13:MySQL 什么时候用到行锁,什么时候用到表锁
当执行 DDL 语句去修改表结构时,会使用表锁。
当增删改查匹配到索引时,Innodb 会使用行锁
如果没有匹配不到索引,那么就会直接使用表锁
sQL Select 语句完整的执行顺序
SELECT 语句的逻辑执行顺序:从“仓库”到“结果”
-
FROM <表名>:从哪里开始? 🗺️
-
JOIN <表名> ON <条件>:把相关数据“拼”起来 🧩
-
WHERE <条件>:第一次“粗筛”数据 🧺
-
GROUP BY <列>:按类别“打包”数据 📦
-
HAVING <条件>:对“打包”后的结果进行“精筛” 🕵️♀️
-
SELECT <列/表达式>:确定最终要“展示”什么 🖼️
-
DISTINCT:去除重复,只留“唯一” 🎯
-
ORDER BY <列/表达式>:给结果“排排序” ⬆️⬇️
-
LIMIT <偏移量>, <行数>:只取“前几名”或“某一段” ✂️
回表
回表是指MySQL在使用索引查找数据时,首先通过索引查找到数据的主键或唯一键,然后再根据该主键或唯一键去数据表中查询真实数据的过程
RabbitMQ生产者-->交换机-->队列
交换机用来接受生产者发送的消息并将这些消息发送给绑定的队列,**即:生产者-->交换机-->队列
RabbitMQ的5大核心概念:
Connection(连接)、Channel(信道)、Exchange(交换机)、Queue(队列)、Virtual host(虚拟主机)。
RabbitMQ的五种模型
1.基本消息模型:生产者–>队列–>一个消费者 2.work消息模型:生产者–>队列–>多个消费者共同消费 3.订阅模型-Fanout:广播,将消息交给所有绑定到交换机的队列,每个消费者都可以收到同一条消息 4.订阅模型-Direct:定向,把消息交给符合指定 rotingKey 的队列(路由模式) 5.订阅模型-Topic:通配符,把消息交给符合routing pattern(主题模式)的队列
RabbitMQ交换机
有四种类型:Direct, topic, Headers and Fanout
-
Direct (默认)直接交换器,工作方式类似于单播,Exchange会将消息发送完全匹配ROUTING_KEY的Queue
-
fanout 广播是式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue。
-
topic 主题交换器,工作方式类似于组播,Exchange会将消息转发和ROUTING_KEY匹配模式相同的所有队列, * 表是匹配一个任意词组,#表示匹配0个或多个词组
RabbitMQ保证顺序消费不重复消费
只需要一个队列配置一个消费者
多个队列,保证每组顺序消费的消息发到同一个队列中,给这些消息设置一个统一的全局id即可 设置队列的“ x-single-active-consumer“:单活模式,表示是否最多只允许一个消费者消费 从第一个顺序消费 常见mq实现订单超时的处理
rabbitmq 保证消息持久化可靠性(消息不丢失)
1**、开启事务(不推荐)**
2**、开启** confirm(**推荐)**
3**、开启** RabbitMQ 持久化**(交换机、队列、消息)**
4**、关闭** RabbitMQ 自动 ack(**改成手动)**
1、生产者保证 (1) 开启消息确认机制(Publisher Confirms)
// 启用 Confirm 模式 channel.confirmSelect();
2、中间件保证 交换机、队列、消息 持久化
java如何排查线上问题
明确症状:确认是CPU飙升、内存泄漏、线程阻塞、响应超时,还是频繁Full GC。
查看监控:使用Prometheus、Grafana、Zabbix等工具查看系统指标(CPU、内存、线程、GC次数、请求量等)。
检查日志:通过ELK(Elasticsearch、Logstash、Kibana)或分布式日志系统搜索错误日志(如ERROR、Exception)。
-
CPU占用过高 定位高CPU线程:
jps -l # 查看java 进程 获取pid top -H -p <pid> # 查看进程内各线程CPU占用
内存泄漏/OOM
-
查看线程状态:
jstack <pid> > thread.txt
-
搜索
BLOCKED
、WAITING
状态的线程,分析代码锁竞争。
-
频繁Full GC 检查GC日志:
JVM参数添加 -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps。
使用 GCViewer 或 GCEasy 分析GC日志,观察老年代回收效率。
常见原因:
内存泄漏(通过堆快照分析)。
JVM参数不合理(如堆大小、Survivor区比例)。
限流、降级策略
全局异常处理实战
注解ControllerAdvice配合ExceptionHandler实现全局异常处理 转到一个错误页面。
创建BaseException extends runExceptionHandler
2.全局异常处理
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler {
@ExceptionHandler(BaseException.class)
}
IOC 是什么?
控制反转
• 将对象之间的相互依赖关系交给 IOC 容器来管理,并由IOC 容器完成对象的注入
工厂一配置好配置文件/注解即可,完全不用考虑对象是 如何被创建出来的
如果利用 IOC 的话,你只需要配置好文件/注解,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。
final、finally、finalize的区别*
final:java关键字,修饰类、不能被继承,修饰变量或方法,不能修改或重写 finally:异常处理的一部分,只能在try/catch语句中使用,表示finally中的代码一定会执行 finalize:Object中的方法名称,在GC启动且对象将要被回收时由系统调用,不需要程序员手动调用
重写和重载的区别
重载
一个类中,有多个方法名相同,但参数个数和 参数类型不同
与返回值无关,与权限修饰符也无关。
重写
方法,方法名,参数列表和返回值都必须相同
权限修饰符不能小于被重写方法的修饰符。
重写的方法不能抛出新的异常
简述一下你对反射的理解?
类获取这个类的所有属性和方法
对象调用它的任意一个方法和属性
先获取到该类的字节码文件对象(.class), 就能够通过该类中的方法获取到我们想要的所有信息
MyBatisPlus 中 QueryWrapper 动态条件
IOC
JDBC
反射实现的方式
能够运行时动态获取类的实例
第一种:通过Object类]getClass方法 第二种:通过对象实例方法获取对象 第三种:通过Class.forName方式
抽象类和接口的区别
接口中的成员变量只能是 常量public static final 类型的;
接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静 态方法; 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
抽象类可以在不提供接口方法实现的情况下实现接口。
Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,或者是public。
String 和StringBuffer与StringBuilder的区别?
允许我们在不创建新字符串对象的情况下修改字符串。
String 对象是不可变的String 由于有 final 修饰 操作少量的数据 = String
StringBuffer线程安全 ,多个线程可以同时访问和修改StringBuffer对象而不会引发数据不一致的问题。
StringBuffer 用synchronized关键字来实现线程安全,单线程环境降低性能。
StringBuilder不是线程安全的,多线程会导致数据不一致或未定义的行为。
它在单线程环境中比StringBuffer具有更好的性能。
-
StringBuffer:适用于多线程环境中需要安全地修改字符串的场景。
-
StringBuilder:适用于单线程环境中需要高效地修改字符串的场景。
执行速度 StringBuilder>StringBuffer>String
如何选择合适的持久化方式
如果是数据不那么敏感,且可以从其他地方重新生成补回的,那么可以关闭持久化。
如果是数据比较重要,不想再从其他地方获取,且可以承受数分钟的数据丢失,
比如缓存等,那么可以只使用 RDB。
如果是用做内存数据库,要使用 Redis 的持久化,建议是 RDB 和 AOF 都开启,
或者定期执行 bgsave 做快照备份,RDB 方式更适合做数据的备份,AOF 可以保
证数据的不丢失。*补充:**Redis4.0*** *对于持久化机制的优化*
Redis4.0 相对与 3.X 版本其中一个比较大的变化是 4.0 添加了新的混合持久化方式。
简单的说:新的 AOF 文件前半段是 RDB 格式的全量数据后半段是 AOF 格式的增量
数据
•
*优势*:混合持久化结合了 RDB 持久化 和 AOF 持久化的优点, 由于绝大部分
都是 RDB 格式,加载速度快,同时结合 AOF,增量的数据以 AOF 方式保存了,
数据更少的丢失。
Redis哨兵和集群的区别
Redis哨兵模式采用主从架构,有一个主节点和多个从节点,主节责写,从节点负
Redis哨兵模式通过哨兵节点实现故障转移,能够做到主节点宕机时快速切换,保证高可用性;
Redis哨兵模式部署和维护比较容易,一旦发现了主节点宕机,新的主节点可以很快地被选举出来;
而Redis集群采用分片架构,将数据分散存储在多个节点上,每个节点都可以同时进行读写操作。 Redis集群通过分片的方式实现数据的水平扩展,能够支持更大的数据量和更高的并发请求。 Redis集群部署和维护比较复杂,需要考虑数据的分布、节点的负载均衡和故障转移等问题。
Redis哨兵模式适用于简单的主从复制场景,对于少量的节点和数据负载是足够的;
而Redis集群适用于大规模的数据存储和高并发访问,可以实现数据的分片和水平扩展。
*劣势*:兼容性差,一旦开启了混合持久化,在 4.0 之前版本都不识别该 aof 文件,
同时由于前部分是 RDB 格式,阅读性较差。
Redis 持久化机制 RDB 和AOF 区别?
附加问题:都开启优先加载AOF
1RDB ---快照持久化机制,它会在指定的时间间隔内,将内存中的数据快照保存到磁盘上。 二进制文件
优点:rdb速度快 适合快速备份和恢复大量数据 体积小数据 加载快 存储慢,恢复快
缺点:
-
不实时:无法做到数据实时持久化,会丢失最近一次快照后的数据。
-
性能波动:在大量数据写入时,由于需要Fork子进程来生成RDB文件,可能会导致内存占用较高和性能波动。
适用场景:
-
适用于对数据实时性要求不高、恢复速度要求高的场景,如定期备份和数据恢复。
-
适用于读多写少的场景,如缓存系统。
2AOF以日志方式 将每个写操作记录到文件中,在Redis重启时,可以通过重新执行这些写操作来恢复数据。AOF文件默认名为appendonly.aof。
优点:
-
数据安全性高:可以实时保存数据,减少数据丢失风险。提供更高的数据安全性和实时性
-
可读性:AOF是文本格式,便于读取和修改。
缺点:
-
文件体积大 因为需要逐条命令执行,恢复速度较慢
适用场景:
-
适用于对数据安全性要求高的场景,如在线交易、实时监控等。
可以使用RDB进行定期备份,同时使用AOF来确保数据的实时性和安全性。
3混合持久化 如果你的业务场景既要兼顾性能,又注重数据完整性,那么可以混合持久化的方式
如果是用做内存数据库,要使用 Redis 的持久化,建议是RDB 和AOF 都开启,或者定期执行 bgsave 做快照备份,RDB 方式更适合做数据的备份,AOF 可以保证数据的不丢失。
劣势:兼容性差,一旦开启了混合持久化,在 4.0 之前版本都不识别该aof 文件,同时由于前部分是 RDB 格式,阅读性较差。
如果你对数据丢失无所谓且可以从其他地方重新生成补回的,追求性能最大化的情况下,甚至可以禁用持久化。
Redis集群
1:主从复制 一个主一个从或多个从 一个 从节点从主节点复制数据,可以实现读写分离 主节点做写,从节点做读
适用场景 需要高可用、负载均衡的场景。 数据读多写少的应用,如缓存系统、会话存储等。
2:哨兵(Sentinel)
从主从中增加了哨兵的功能,用于监控主节点的状态,当主节点宕机之后会自动进行故障转移 进行投票重新选出主节点。
哨兵的宕机分为两种:主观宕机 和客观宕机 ,当客观宕机了之后就会再选举一个从节点作为主节点,而这又可以分为两步
选主节点要遵循以下原则
a:健康性:从节点响应的时间 b:完整性:根据从节点备份的完整性,根据数据备份偏移量 c:稳定性:启动时间周期,心跳检测 d:如果以上三个条件都相等,则根据节点启动时分配的run id来分配,runid越小越有可能被选择为主节点 **
-
需要高可用、自动容错的环境。
-
对数据安全性要求较高的应用,避免单点故障。
3:Cluster 多主多从 通过将数据分片存储在多个实例中来实现分布式存储, 一定程度上解决了哨兵模式下单机存储有限的问题,且支持自动分片、负载均衡和故障转移
-
• 需要处理大规模数据和高并发请求的应用。
-
• 对扩展性要求较高的分布式应用,如大规模缓存系统、分布式任务队列等。
Redis的缓存雪崩、缓存穿透、缓存击穿
缓存穿透是指大量请求频繁访问数据库中不存在的数据给服务器造成巨大的压力。
解决方案
1.对空值进行缓存:虽然数据不存在,但是我们可以将空值放到redis缓存中,让其后续的访问都从redis查询,从而减小数据库的压力,但是要注意给空值设置过期时间,最多不能超过五分钟。
2.采用布隆过滤器
3.进行实时监控:当发现redis命中率急速降低时,可以排查访问对象,设置访问黑名单。
缓存击穿
有但数据库中有,如果同一时间访问量过大会使数据崩掉。
某个被频繁访问的热点数据,在一瞬间失效,从而导致大量对该数据的请求直达数据库,瞬间对数据库造成巨大的压力,使数据库挂掉。
解决方案
1.预先设置热点数据,在redis高峰访问之前,把一些热点数据提前存入到redis里,延长过期时间。
2.实时调整:监控redis,实时调整热门数据的过期时常。
加分布式锁,一条数据访问数据库
缓存雪崩
缓存中的数据正好在一个时间删除,当请求来时穿过缓存访问数据库。
缓存雪崩是指大量缓存失效,从而导致大量对应数据的请求短时间内直达数据库,对数据库造成巨大的压力,使数据库挂掉。
解决方案:
1.使用多级缓存架构:nginx缓存+redis缓存+其他缓存等。
2.使用锁或者队列:使用锁或者队列避免大量请求对数据的并发访问,不适用于高并发情况。
3.设置过期标识更新缓存:设置一个缓存过期的提前量,当这个提前量过期时会触发另外的线程去更新实际的key的缓存
4.均匀分配过期时间,当我们给key设置过期时间时,可以在失效时间的基础上设置一个随机值,从而让不同的key的失效时间分散开,从而减少数据库的压力
Redis 内存淘汰策略?
由于内存有限,缓存系统必须遵循一些淘汰策略来删除一些不再需要的键.在Redis中,缓存淘汰策略是由maxmemory和maxmemory-policy两个配置参数控制的
缓存淘汰策略
当Redis的内存达到maxmemory配置的值时,Redis会尝试删除一些键,以便为新键腾出空间。Redis支持以下五种缓存淘汰策略:
-
noeviction: 当Redis的内存达到maxmemory时,不执行任何操作,而是返回错误。
-
volatile-lru: 在过期的键中使用LRU算法进行淘汰。
-
volatile-ttl: 在过期的键中,按照剩余存活时间从小到大进行淘汰。
-
volatile-random: 在过期的键中,随机选择一个进行淘汰。
-
allkeys-lru: 使用LRU算法从所有键中进行淘汰。
Redis 提供 6 种数据淘汰策略:
Redis 的内存淘汰策略共有 8 种具体的淘汰策略,默认的策略为 noeviction,,当
内存使用达到阈值的时候, 所有引起申请内存的命令会报错。
将要过期+最少使用+任意选择
• volatile-lru(least recently used最少使用):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰•
allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
4.0 版本后增加以下两种:
• 最不经常使用的数据淘汰
• allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key
我们在选择使用淘汰策略的时候可以根据访问 key 的方式来选择不同的淘汰策略
1、当我们 redis 中的 key 基本上都有用到,也就是说每个 key 都有周期性访问
到,那就可以选择使用 random 策略
2、当我们 redis 中的 key 部分是我们经常访问的,部分是非经常访问的就可以考
虑使用 LRU 和 LFU 策略
3、当我们想根据时间长久淘汰超时数据时,就选用 ttl
4、我们根据我们的需要是否有要长久保存的 key 来选择 volatile 或者是 all,如果
有需要长久保存的 key,则使用 volatile,否则可以使用 all 全表扫描
Redis 内存淘汰机制
1、从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
2、从已设置过期时间的数据集中挑选将要过期的数据淘汰
3、从已设置过期时间的数据集中任意选择数据淘汰
4、从已设置过期时间的数据集中挑选最不经常使用的数据淘汰 (4.0增加)
5、当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key (4.0增加)
6、当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
7、从数据集中任意选择数据淘汰
8、内容满了之后写入报错(几乎没人使用)