自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(147)
  • 收藏
  • 关注

原创 【Spring 三级缓存】十分钟搞懂 Spring 循环依赖解决方案

当执行 populateBean 中,如果 Bean A 需要填充 Bean B,此时将需要调用 getBean(B) 方法去创建 Bean B,如果 Bean B 又依赖了 Bean A,此时就会通过 getBean(A) 方法获取 Bean A,此时就会回到前面 2.1 中的步骤,去检查 Bean 是否位于缓存中;的角色,当创建 A 的时候需要 B 对象的创建,此时 A 就处于一个 “中间状态”,在创建 B 的时候,发现其依赖 A,此时将这个中间状态的 A 注入 B,就破除了这个循环。

2025-04-13 17:27:04 1184

原创 关于 Java 字符串常量池的简明讲解

JVM 为了提高性能和减少内存开销,在实例化字符串常量的时候,为字符串开辟了一个字符串常量池(String Constant Pool),类似于缓冲区。字符串常量池的底层是 HotSpot 的 C++ 实现,它是一个 StringTable(类似于 Java 中的 HashTable),保存的本质上是字符串对象的引用。

2024-12-08 16:16:21 816

原创 万字详谈,Bitmap、布隆过滤器、布谷鸟过滤器|附误判率计算、布谷鸟过滤器源码分析

Bitmap(位图),顾名思义,是一种以二进制位(bit)来表示数据的特殊数据结构。在编程中,我们往往需要记录某种状态,比如签到系统中的用户签到状态,答题中的每道题作答状态,对于这种只有两种情况的状态,如果使用传统的数据结构,往往需要非常多的存储空间;比如我们使用用户 id 来存储用户状态,比如使用 java 中的 int,每个 id 就需要 4 字节的存储空间;但是 Bitmap 通过将每一个状态(0或1)直接映射为一个位,就大大的节省了空间。

2024-11-08 08:41:22 1183

原创 Redis 权限控制(ACL)|ACL 命令详解、ACL 持久化

您希望通过限制对命令和密钥的访问来提高安全性,以便不受信任的客户端没有访问权限,而受信任的客户端仅具有执行所需工作所需的数据库的最低访问级别。例如,某些客户端可能只能执行只读命令。您希望提高操作安全性,以便不允许访问 Redis 的进程或人员因软件错误或手动错误而损坏数据或配置。例如,从 Redis 获取延迟作业的工作程序无法调用 FLUSHALL 命令。

2024-11-05 18:52:27 2386

原创 Redis 中的定期删除和惰性删除究竟是怎样实现的?

每当一个 Key 被设置了过期时间的时候,Redis 会把该 key 带上过期时间存储到一个过期字典(expires dict)中,也就是说「过期字典」保存了数据库中所有 key 的过期时间。

2024-11-01 11:22:27 1346

原创 MySQL 中的事务隔离级别到底是怎样实现的?ReadView 和 MySQL 隐藏列的详细解析

Read View 主要用于在事务执行期间确定哪些版本的数据对当前事务可见。在多版本并发控制中,数据库会为每个事务创建一个 Read View,通过这个 Read View,事务可以看到在其开始时已经提交的数据版本,而不会看到在其执行过程中其他事务未提交的数据或者已提交但对当前事务不可见的数据。

2024-10-28 17:01:02 919

原创 一套模板彻底解决螺旋矩阵问题

与上一题不同的是,本题需要我们自己生成矩阵,但本质还是矩阵的螺旋遍历,修改一下上面的代码即可。这一类题目的思路其实是比较简单的,就是按照题目中给的顺序,右、下、左、上来螺旋遍历数组。首先从最上层开始,从左向右遍历,也就是不断更新列索引;当完成了最高层的遍历,更新剩余未遍历的元素,此时的高边就应该更新为。,也就对应了上面说的转折点在转折之前遍历。说明没有剩余的元素了,结束循环输出结果。在最右边,从上向下遍历的时候,起点是从。,返回矩阵中的所有元素。,没有去遍历之前的转折点。对应力扣第 59 题「

2024-10-25 14:57:02 969

原创 JMM 模型、synchronized、volatile 关键字全解

JMM(Java 内存模型)可以看作是针对多线程环境下内存可见性、有序性和一致性问题的一种抽象解决方案。主内存与工作内存的抽象:JMM 将内存划分为主内存(共享内存)和工作内存(线程私有的缓存),通过这两者的抽象,解释了线程如何通过工作内存与主内存进行数据交互。volatile、synchronized等具体实现:这些关键字是 JMM 规则在 Java 语言中的具体表现,它们提供了线程安全的基本工具,用于确保多线程中的变量可见性、操作的有序性和原子性。happens-before 规则的抽象。

2024-09-13 17:38:01 908 2

原创 【线程池源码详解】|关于线程池,你想知道的都在这里!

线程池是一种包含若干线程的集合,线程池管理这些线程的生命周期(包括创建、调度、执行、终止等),使用了线程池,就不需要程序员再去编写线程创建和销毁的代码,而是将需要执行的的任务提交到线程池,由池中的线程来执行这些任务。

2024-09-10 17:41:38 1348 1

原创 【ArrayList 扩容机制源码解析】|打破屏障,彻底搞懂底层扩展机制

这里首先列出 ArrayList 扩容的几个特点,看完这些特点再去阅读体验会比较好1)`ArrayList` 中维护了一个 `Object` 类型的数组,`elementData`。2)当每次创建 `ArrayList` 对象的时候,如果使用的是无参构造器,则初始的 `elementData` 的容量为 0,第一次添加的时候则扩容 `elementData` 的容量为 10,如果需要再次扩容,则扩容为原来的 `1.5` 倍3)如果使用的是指定大小的构造器,则初始的 `elementData` 的

2024-08-30 10:23:02 784

原创 【ThreadLocal 与 InheritableThreadLocal 源码解析】:数据存取 | 线程属性继承

ThreadLocal ,从字面含义上来看就是:“线程本地”,这形象的说明了它的用处: ThreadLocal 正是 Java 提供的一种线程本地存储机制,可以利用该就只将数据还存在某个线程的内部,该线程可以在任意的时刻、任意的方法中去获取缓存的数据。

2024-07-20 17:52:25 1339

原创 【Spring AOP 源码解析】彻底搞懂 AOP 是如何执行的

Spring 在真正的通过反射去执行实际调用的方法之前,会有一个名为 **`intercept()`** 的方法,执行一些拦截的逻辑;我们构造的这些切面方法实际上就是在这部分中执行的;Spring 在创建 Bean 的时候会根据 AOP 注解生成一个由一组 interceptor 组成的链式结构,然后在调用实际方法之前,通过循环的方式按照顺序去执行这些 interceptor 中的代码,这样就在合适的时机去执行了合适的代码。

2024-07-12 15:07:50 1233

原创 【Spring AOP 源码解析前篇】什么是 AOP | 通知类型 | 切点表达式| AOP 如何使用

这样,我们虽然每次都不用去复制代码了,但还是需要在我们需要的位置去调用这个接口,而调用这个代码的位置其实就是 切面。我们用具体的代码来看一下,下面实现了一个统一的接口 BeforeAdvice,然后在每个方法之前去调用它。

2024-07-07 22:12:41 1509 3

原创 源码航行阅读目录

在准备面试和学习的过程中,我阅读了比较多的源码,比如 JUC、Spring、MyBatis,收获了很多代码的设计思想,也对平时调用的 API 有了更深入的理解;但过多散乱的笔记给我的整理复习带来了比较大的麻烦。📋 在 C 站零零散散发了 JUC 的源码解析和集合源码解析,收到了很多朋友的喜爱,这里我准备将一些源码解析的文章整合起来,为了方便阅读和归纳在这里整合成目录。🌊🌊🌊 让我们一起在源码的海洋中启航吧!

2024-07-06 20:47:18 435

原创 @Transactional 源码级解析|彻底搞懂注解失效原因

注解在 Spring 框架中用于管理数据库事务。它可以应用于类或方法级别,以定义在事务中执行的代码。事务是指一组逻辑上的操作单元,这些操作要么完全执行成功,要么完全失败回滚。确保这些操作要么全部提交到数据库,要么在发生异常时全部回滚,以保持数据的一致性和完整性。:定义事务的传播行为,例如 REQUIRED等。isolation:定义事务的隔离级别,例如 READ_COMMITTED等。timeout:设置事务的超时时间(秒)。readOnly:将事务标记为只读,适用于不修改数据的操作。

2024-07-06 10:45:12 1039

原创 Docker 常见命令快速查阅

指令说明FROM指定基础镜像ENV设置环境变量,可以在后面的指令中使用COPY拷贝本地文件到镜像中的指定目录RUN执行 Linux 的 Shell 命令,一般是安装过程的命令EXPOSE指定容器运行的时候监听的端口,提供给镜像使用者当作参考ENTRYPOINT容器入口命令,镜像中应用的启动命令,容器运行时调用OPTIONS 说明。

2024-06-25 22:53:59 1188 1

原创 还不会线程池?JUC线程池源码级万字解析

是 Java 中 java.util.concurrent包的一部分,用于管理线程池的实现。它提供了一种灵活的方法来创建和管理线程池,以便有效地执行大量的任务。它允许开发人员配置线程池的各种参数,如核心线程数、最大线程数、线程闲置时间、任务队列等。简单来说,它就是一个内部维护了一个线程池的任务执行器(Executor)。在正式开始阅读源码之前,先来看一下应该如何使用这个它来执行任// 构造线程池执行器4,10,i >= 0;// 关闭线程池。

2024-06-08 14:39:00 1005 1

原创 23种设计模式全面总结 | 快速复习(附PDF+MD版本)

由于工厂模式在父工厂中定义了一个抽象的实例化方法,这也就导致了通过工厂模式只能创建一类的实例,这是工厂模式的限制;而抽象工厂类将解决了这个问题。也就是提供多个不同的接口来实现不同大类的创建。但这样将引起了一个问题,当我们去新增工厂能够创建的类的时候,又必须去修改抽象的父工厂,又回到了之前简单工厂的问题,即违反了开闭原则。

2024-05-27 09:52:06 1965

原创 初探 JUC 并发编程:Java 中的并发队列 ConcurrentLinkedQueue 源码级解析

offer 操作介绍offer 操作是在队列的末尾添加一个元素,由于队列是无界队列,所以一定会返回true;当传入的值为 null 的时候,会抛出 NPE 异常。// e 为空则抛出空指针异常// 构造 node 节点// 从尾节点开始插入;) {// p 的下一个节点为空,说明 p 是最后一个节点// 通过 CAS 操作设置 p 节点的 next// 每插入两个节点的时候会执行这个方法if (p!= t)// 当 p 节点(指向的是尾部节点,发生自旋的的时候)

2024-05-14 14:48:55 890

原创 初探 JUC 并发编程:读写锁 ReentrantReadWriteLock 原理

然后去判断当前线程是否应该被阻塞,也就是 AQS 队列的队头是不是请求的写锁,然后去判断最后一个获取到锁的线程是不是本线程,如果不是的话,检查线程中的 readHolds 是否为 0(如果为 0 则说明没有获取到锁,如果获取到了锁这里应该置为 1),因为 get 方法会向线程的 ThreadLocal 中添加对象,所以在确定它没有得到锁之后清楚 ThreadLocal 中的内容。

2024-05-10 20:53:06 912

原创 初探 JUC 并发编程:独占锁 ReentrantLock 底层源码解析

`ReentrantLock` 中提供了以上的两种构造方法,其作用和引言中说的相同,即构造公平锁或者非公平锁,`ReentrantLock` 中的内部类 `Sync` 这个类直接继承了 `AQS` ,它的两个子类 `FairSync` 和 `NonfairLock`分别实现了公平锁和非公平锁, `ReentrantLock` 类中的核心方法都是调用这两个子中类的方法来实现的。

2024-05-10 11:44:39 1190

原创 Netty 网络编程深入学习【一】:ByteBuffer 源码解析

ByteBuffer是一个用于处理字节数据的缓冲区类。它是Java NIO 包的一部分,提供了一种高效的方式来处理原始字节数据。ByteBuffer可以用来读取、写入、修改和操作字节数据,它是一种直接操作字节的方式。

2024-05-03 13:35:05 776

原创 初探 JUC 并发编程:Java 并发包中并发 List 源码剖析

并发包中的并发 List 只有。这是一个线程安全的ArrayList,对其进行修改的操作都是在底层的一个复制数组上进行的,也就是使用了写时复制策略。每个/***/上面的注解的含义是这样的:保护所有变化的锁。(我们对内置监控器略有偏好,而不是,两者都可以。这个锁的类型要根据不同的 Java 源码来看,不同的团队会有不同的设计选择,所以如果追源码发现这个锁的实现不同,是因为我们看的源码的版本不同。这里使用的就是独占锁。通过上面源码的阅读,可以发现,

2024-04-29 20:52:57 1483 2

原创 初探 JUC 并发编程:ThreadLocalRandom 原理剖析

ThreadLocalRandom 的继承关系是这样的,它继承了 Random 类并且重写了 nextInt 方法,ThreadLocalRandom 类中使用的种子存放在调用线程的 threadLocalRandomSeed 变量中,当线程调用了 ThreadLocalRandom 类的 current() 方法的时候,ThreadLocalRandom 会去初始化调用线程的 threadLocalRandomSeed 变量,也就是初始化种子。

2024-04-28 21:33:30 1040

原创 LeetCode 热题 100 题解:二叉树部分(1 ~ 5)

所谓中序遍历就是按照这个顺序去遍历处理一个**节点,**即 左子树、节点、右子树这样的方式,所以对于一个节点的处理方式就是这样的:遍历它的左子树、记录节点的值、遍历它的右子树对每个节点都要进行上述的操作,而递归解法就可以实现这样的效果,只需要将上面的逻辑想清楚,剩下的交给递归去做就可以了。

2024-04-27 16:04:56 622

原创 LeetCode 热题 100 题解:普通数组部分

其中会有一个极端的情况,假如数组的长度为 N,而数组中的元素恰好就是 1 ~ N 中的所有元素,那此时最小的正数就是 N + 1;那第一个思路就很简单了,首先创造一个新的数组,然后对于原数组先从 length - m 遍历到末尾,然后再遍历 0 到 length - m - 1 这部分的内容,将这些内容填充到新的数组中。如果不考虑 0 的情况下,本题的思路其实是比较容易的,就是先计算出整个数组的乘积,然后遍历到数组中的某个元素的时候,用这个乘积去除以这个元素,得到的结果放到 answer 数组中。

2024-04-18 18:29:35 1202

原创 LeetCode 热题 100 题解(二):双指针部分(2)| 滑动窗口部分(1)

比如上图中的红色部分,它存储水的容量其实就是 **左边的最大高度** 和 **右边的最大高度** 的 最小值,减去这里的格子高度(案例中为 0),在上面的案例中,左边的最高高度为 2,右边的最高高度为 3。所以本题的暴力解法就比较好想了,找到其左边最大高度,再找到其右边的最大高度,通过上面的规律进行运算。

2024-04-10 17:45:07 832

原创 LinkedHashMap 是如何保证返回的顺序性的?

读到这里其实就可以大致了解到 LinkedHashMap 的机制,就是将 HashMap 中的 Node 节点替换为了类中的 Entry,新增了 before 和 after 节点来创造出一个依据顺序连接的双向链表,由此来达到存储插入顺序的目的。首先获取了此时的 last 节点,也就是链表的最后一个元素,然后做了一个判断,如果 last 是空的,就说明此时数组中没有元素,是第一次添加,此时就将 head 也置为 p 节点,否则就将 p 与 last 节点双向连接。

2024-04-10 10:57:44 1397 2

原创 LeetCode 热题 100 题解(二):双指针部分(1)

上面代码展示的就是遍历第一个元素的逻辑,首先要保证 i 不会越界,其次要保证 nums[i] 是小于等于零的,当发现 nums[i] > 0 的时候就说明本次的查找已经结束了,直接将 res 返回;第二段 if 进行去重的,就是如果发现 nums[i] == nums[i - 1] (和上一个相同),此时就直接遍历下一个元素。

2024-04-09 18:16:42 682

原创 万字源码解析!彻底搞懂 HashMap【二】:putVal 方法和 resize 方法(重点)

面试题引入:什么重写equals()方法的同时需要重写hashCode()方法?HashMap 的初始化大小为什么是 16?说一下 HashMap 的扩容。

2024-04-09 13:36:18 1295

原创 万字源码解析!彻底搞懂 HashMap【一】:概念辨析与构造方法源码解析

这里指定的是默认的负载因子的值,为 0.75,负载因子(Load Factor)是指哈希表中已存储元素数量与哈希表容量的比例。在哈希表中,负载因子用于衡量哈希表的填充程度,即已存储元素占哈希表容量的比例。通常情况下,负载因子是一个介于 0 到 1 之间的数值,在哈希表中,当负载因子达到一定阈值时,通常会触发哈希表的扩容操作,以保持哈希表的性能。常见的默认负载因子值为 0.75,这是一个经验值,可以在平衡内存占用和性能之间做出权衡。

2024-04-08 14:35:21 828

原创 LeetCode 热题 100 题解(一):哈希部分

如果说当前遍历到 7,从开头到 7 是否遍历过 2 即可;但是这样每次都要从头开始遍历,时间开销比较大。那能不能通过一个映射关系将每个数据是否出现和出现的位置存储下来,然后通过查询这个映射关系,来快速得知数组中是不是存在这个元素了呢?比如上面的情况,当遍历到 2,先查询前面是否遍历到过 target - 2,如果没有就将 2 存储下来,并且与其出现的位置做一个映射;此时当遍历到 7 的时候,就可以通过查询这个映射来得知 2 是否出现过和其最后一次出现的下标是什么了。

2024-03-29 22:00:56 1100

原创 六千字详解!一篇看懂 ArrayList 的扩容机制(完整源码解析)

这是一个共享的(static)空数组实例,被用作使用 默认无参构造方法 时,elementData 的默认值;它的作用是与另一个共享的空数组实例来做区分,那另一个共享数组为 EMPTY_ELEMENTDATA,它在接下来要讲的 有参构造方法 中具有很重要的作用;简单来说 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是标识着通过无参构造形成的空 ArrayList,而 EMPTY_ELEMENTDATA 是通过有参构造形成的空 ArrayList,它们在后续的扩容策略中会有所不同。

2024-03-29 21:05:03 3391 1

原创 代码随想录刷题笔记 Day 59 | 两个字符串的删除操作 No.583 | 编辑距离 No.72

同时观察到递推公式依赖的是左上角,也就是此时要初始化第一行和第一列:第一行的含义是 长度为 0 的字符串1和字符串2变为相同需要多少次,让一个有长度的单词变为长度为 0,那就只有一种删除操作了,需要的次数是单词的长度次;比如上图的情况,这里发现两个 a 是相同的,此时要想让这两个字符串相同,就需要绿色部分也相同,也就是要加上使得绿色部分相同的操作的次数,这个次数正是。那什么时候能保证两个单词都保留的最多呢?代表将 i - 1 长度的单词 1 和 j - 1 长度的单词 2 变为同一个单词需要的最少的步数。

2024-03-27 14:40:30 915

原创 代码随想录刷题笔记 Day 58 | 判断子序列 No.392 | 不同的子序列 No.115

本题是要查询 s 中有多少种方法可以得到 t,比如第一个案例 s = “rabbbit”, t = “rabbit”,首先来考虑如何划分这个子问题:既然我去查询 s 有多少种方法可以得到 “rabbit” 比较困难,那能否先去找方法得到 “t” 呢?在这种情况下,你会怎样改变代码?s 的前 m 个元素和 t 的前 n 个元素的公共子序列的长度,是可以通过 m - 1 和 n - 1 组成的公共子序列的长度推出的。表示 s 的钱 i - 1 个元素和 t 的前 j - 1 个元素构成的最长公共子序列的大小。

2024-03-26 17:19:56 1206

原创 代码随想录题解 Day 57 | 最长重复子数组 No.718 | 最长公共子序列 No.1143 | 不相交的线 No.1035 | 最大子数组和 No.53

又是一个关于子数组的题目,子数组也就代表着连续,这样就代表着状态中必须包含以什么为 结尾。所以本题中的状态就可以初步确定为以 nums[i] 为结尾的数组的最大的总和。

2024-03-25 17:14:56 685

原创 代码随想录刷题笔记 Day 56 | 最长递增子序列 No.300 |最长连续递增序列 No.674 | 最长重复子数组 No.718

本题的初始化和之前有所不同,注意这个递推公式:dp[i][1] = Math.max(dp[i][1], dp[j][1] + 1); 如果简单的将这个值初始化为 0,那如果前面没有比 num[i] 小的值,那这个值就会 保持 0,而通过题意可以直到,这个值应该为 1。所以所有的 dp[i][1] 都应该初始化为 1。

2024-03-21 23:35:06 717

原创 代码随想录刷题笔记 Day 55 | 买卖股票的最佳时机含冷冻期 No.309 | 买卖股票的最佳时机含手续费 No.714

本题仍然是讨论第一天的初始化。对于买入的状态很容易,为 -prices[0];而对于卖出的状态,可以知道,第一天对于卖出的状态是没有意义的,所以要考虑初始化成什么不会对第二天产生影响,先来看这个状态在第二天哪里用到了:

2024-03-20 15:05:56 1116

原创 代码随想录刷题笔记 Day 54 | 买卖股票的最佳时机 III NO.123 | 买卖股票的最佳时机 IV No.188

因为第一次使用的是下标为 0 的部分,所以 temp2 的值是不需要初始化的,这样就完成了递推公式的推导。再来看初始化,直接初始化为 Integer.MIN_VALUE 是有可能引发越界的,上一题因为只初始化了第一天所以不会产生影响,而本题就不同了。所以要找一个比所有卖出状态下 dp 数组的值还要小的一个值来初始化数组。而恰好题目中提到了,prices[i]

2024-03-18 10:14:29 960

原创 代码随想录刷题笔记 Day 53 买卖股票的最佳时机 No.121 | 买卖股票的最佳时机 No.122

与贪心沿着固定的路径进行不同,动态规划其实更偏向于穷举,所以本题的动规解法的时间肯定是要长于贪心的。首先来明确本题中的 状态 是什么,是在某一天通过买卖股票所持有的金钱,但为了描述这个状态,会出现两种情况:当前处于买入的状态,也就是手中还持有股票,持有的金钱为 负数,因为此时只有支出当前处于卖出的状态,手中的股票已经被卖出,持有的金钱为 正数需要注意的是,某一天处于的是 买入 或者 卖出 的 状态,而不是说股票是在这一天买入或者卖出的。

2024-03-17 14:48:18 998

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除