Redis网络模型
Redis网络模型(io多路复用) 阻塞IO(Blocking IO) 假设服务端只开启一个线程处理请求,第一个请求到来,开始调用内核read函数,然后就会发生阻塞,第二个请求到来时服务端将无法处理,只能等第一个请求读取完成。这种方式的缺点很明显,每次只能处理一个请求,无法发挥cpu多核优势,性能低下。 为了解决这个问题,我们可以引入多线程,这样就可以同时处理多个请求了,但服务端可能同时有成千上万的请求需要处理,随之而来的是线程数膨胀,频繁创建、销毁线程带来的性能影响,当然我们可以使用线程池,但服务能处理的总体数量就会受限于线程池线程数量。 非阻塞IO(NON-Blocking...
ConcurrentHashMap底层原理
ConcurrentHashMap底层原理 jdk1.7是数组加链表,它在对象中保存了一个Segment数组。每个Segment元素类似于一个Hashtable;这样,在执行put操作时首先根据hash算法定位到元素属于哪个Segment,然后对该Segment加锁即可,不同的Segment可以并发put。而Segment的锁实现其实是ReentrantLock jdk1.8则是采用了数组+链表/红黑树,他舍弃了Segment数组,用的是CAS +...
SpringIOC
什么是 IoC? IoC (Inversion of Control )即控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题。 例如:现有类 A 依赖于类 B 传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面去取即可。 从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情) 为什么叫控制反转? 控制 :指的是对象创建(实例化、管理)的权力 反转 :控制权交给外部环境(IoC 容器) IoC 解决了什么问题? IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢? 对象之间的耦合度或者说依赖程度降低; 资源变的容易管理;比如你用 Spring...
HashMap
HashMap JDK 7 中 HashMap 的数据结构是数组+链表。 JDK 8 中 HashMap 的数据结构是数组+链表+红黑树。 它在链表长度大于8且数组长度大于64时候会把链表转换成红黑树 HashMap 的初始容量是 16,随着元素的不断添加,HashMap 就需要进行扩容,阈值是capacity * loadFactor,capacity 为容量,loadFactor 为负载因子,默认为 0.75。 扩容后的数组大小是原来的 2 倍,然后把原来的元素重新计算哈希值,放到新的数组中。 负载因子(load factor)是一个介于 0 和 1 之间的数值,用于衡量哈希表的填充程度。它表示哈希表中已存储的元素数量与哈希表容量之间的比例。 负载因子过高(接近 1)会导致哈希冲突增加,影响查找、插入和删除操作的效率。 负载因子过低(接近 0)会浪费内存,因为哈希表中有大量未使用的空间。 HashMap 的put过程: 1.他会先对key计算扰动hash,通过key.hashCode() ^ (key.hashCode() >>>...
Volatile原理
Volatile原理
MySQL 联合索引的最左匹配原则
MySQL 联合索引的最左匹配原则 执行计划基础知识 possible_keys:可能用到的索引 key:实际用到的索引 type: ref:当通过普通的二级索引列与常量进行等值匹配的方式 询某个表时 const:当我们根据主键或者唯一得二级索引列与常数进行等值匹配时,对单表的访问方法就是 const range:如果使用索引获取某些单点扫描区间的记录。 index:当可以使用覆盖 ,但需要扫描全部的索引记录时。 Extra: Using index 索引覆盖 Using Where 当某个搜索条件需要在 server 层进行判断时 Using index for skip scan 跳跃扫描 Using index condtion 索引下推 最左匹配原则 最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。 比如有联合索引 [a、b、c],where 过滤条件中哪些排列组合可以用到索引?(比如这种:where a=xxx b=xxx and c=xxx) 以下排列组合都会走索引:...
redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性) 在项目中,我们主要通过 Redisson 的读写锁机制 来保证数据的强一致性。 当执行读取操作时,我们会加上读锁(共享锁),这样可以做到: 读读不互斥; 读写互斥。 而在更新数据时,我们会加上写锁(排他锁),此时写写、读写都互斥。 这样可以确保在写入数据库的同时,其他线程无法读取缓存数据,从而避免出现脏读或不一致的情况。 这里需要注意的一点是:读写方法必须使用同一把锁,才能真正保证互斥关系成立。 除了使用分布式锁,我们也考虑过使用 “延迟双删”策略 来实现最终一致性。 具体做法是: 先删除缓存; 再更新数据库; 最后延时一段时间后,再删除一次缓存。 不过,延迟的时间点很难精确把握。在延时窗口内仍可能出现脏数据问题,无法满足强一致性场景,因此我们最终没有采用这种方式。 在我最近做的项目中(例如简历中提到的 xxxx 功能), 系统对数据一致性的实时性要求没有那么高,可以接受一定的同步延时。 因此我们采用了 阿里巴巴的 Canal 组件 来实现最终一致性的数据同步。 Canal...
Redis分布式锁redisson看门狗机制
Redis分布式锁方案 使用 Redis 的 SET key value NX EX实现分布式锁时,主要问题是锁过期时间不好设置:如果设置过短,业务未完成锁就过期;设置过长,会降低系统并发度。为此可以使用 Redisson 封装的分布式锁,它内部通过「看门狗机制」自动续期锁(默认锁 30 秒,每 10 秒续期一次),同时通过 Lua 脚本保证加解锁的原子性,从而确保分布式环境下的并发安全。 Redisson分布式锁自动续约机制(看门狗) 线程1尝试tryLock锁未指定锁的过期时间 获取成功后会自动启动看门狗机制 初始加锁: 当调用 lock() 时,Redisson 会通过 Lua 脚本向 Redis 发送加锁命令,设置锁的初始过期时间为 LockWatchdogTimeout(默认 30 秒)。 锁的数据结构为 Hash,键为锁名称,field 为线程 ID,value 为重入次数。 启动定时任务: 加锁成功后,Redisson 会启动一个后台定时任务(通过 Netty 的 HashedWheelTimer 实现),每隔 10 秒执行一次。 ...
LeetCode Hot 100 - 24. 两两交换链表中的节点
LeetCode 24. 两两交换链表中的节点 题目大意 给定一个单链表,需要将链表中的节点按顺序两两交换,并返回交换后新的链表头节点。禁止只交换节点的数值,必须真实地调整指针。当链表长度为奇数时,最后一个节点保持原状。 示例 输入:head = [1,2,3,4] 输出:[2,1,4,3] 当输入为 head = [1,2,3] 时,结果应为 [2,1,3],因为第三个节点无法参与交换。 代码实现 1234567891011121314151617181920212223242526272829303132/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next)...
Redis的数据过期淘汰策略
Redis 的数据过期策略 Redis 采用 「惰性删除 + 定期删除」 两种策略相结合的方式,在 CPU 性能开销 与 内存占用 之间取得平衡。 一、惰性删除(Lazy Expiration) 当客户端访问或修改某个键时,Redis 会在操作前调用 expireIfNeeded() 函数检查该键是否已过期: 若已过期: Redis 会立即删除该键,然后向客户端返回 null。 删除方式由配置项 lazyfree-lazy-expire 决定: 若开启(yes),则采用 异步删除; 若关闭(no),则采用 同步删除。 若未过期: 直接返回该键对应的正常值,不做任何额外处理。 这种方式的优点是 删除时机精准、不会浪费 CPU 时间; 缺点是:若某些过期键一直未被访问,就无法被清除,会长期占用内存。 二、定期删除(Active Expiration Cycle) 为了解决惰性删除的不足,Redis 还会周期性地扫描部分键空间,清除已过期的数据。 1. 检查频率 Redis 默认每秒执行 10 次过期扫描,这一频率由配置文件 redis.conf 中的参数 hz...






