- 博客(77)
- 收藏
- 关注
原创 Mybatis中# 和 $的区别
特性#{}${}处理方式预编译,替换为?占位符直接字符串替换,拼接 SQL安全性防 SQL 注入(安全)存在 SQL 注入风险(不安全)参数类型自动加引号(字符串类型)需手动加引号(字符串类型)适用场景大多数参数传递(用户输入)动态 SQL 结构(表名、排序字段等)最佳实践:优先使用#{},仅在必须动态拼接 SQL 结构时使用${},且务必对${}的参数进行严格校验(如白名单限制)。
2025-10-29 11:12:05
514
原创 Future与CompletableFuture 的区别
它允许在链式调用中主动处理异常(避免最终抛出);若未处理,才会在最终get()join()时抛出,且join()抛出的未检查异常可减少try-catch冗余;异常会在链式调用中向后传播,便于统一处理。这也是 CompletableFuture 比 Future 更适合复杂异步场景的重要原因之一。要不要我帮你整理一份“CompletableFuture 异常处理方法对比表”,涵盖handle等核心方法的用法、场景和区别,方便你实际开发中参考?
2025-10-21 17:14:27
753
原创 事务的 ACID 特性与 Redis 事务实现情况
特性传统数据库Redis 事务说明原子性完全支持 (成功或回滚)部分支持 (无回滚)Redis 保证命令要么全执行要么全不执行,但不支持回滚一致性强保证基本保证Redis 保证数据结构一致性,但业务一致性需应用层实现隔离性多级别 (读未提交到串行化)串行化Redis 天然实现最高隔离级别持久性强保证不保证依赖 RDB/AOF 配置,事务本身不提供持久性。
2025-10-13 09:13:22
575
原创 目录挂载(Bind Mount) 和 卷挂载(Volume Mount)的区别
挂载类型初始状态(新挂载时)核心原因目录挂载空(若宿主机目录空);非空(若宿主机有数据)宿主机目录直接覆盖容器目录卷挂载非空(继承容器目录的默认数据)Docker 自动复制容器数据到新卷目录挂载看宿主机:宿主机目录空,容器目录就空;卷挂载看容器:新卷会 “抄” 容器目录的默认数据,所以初始非空。
2025-10-05 14:22:17
652
原创 Java 中栈(Stack)和队列(Queue)最常用的方法
操作栈 (Stack)队列 (Queue)添加元素push(e)offer(e)移除并返回元素pop()poll()查看元素 (不移除)peek()操作位置尾部 (Tail)尾部添加 (Tail)头部移除 (Head)遵循原则LIFO(后进先出)FIFO(先进先出)
2025-09-25 16:48:25
331
原创 Spring Cloud Gateway 和 Nginx 的区别
选 Nginx:需要高性能静态资源处理、多语言服务转发、简单负载均衡,且不依赖 Java 生态;选 Spring Cloud Gateway:纯 Java 微服务架构,需要动态路由、服务治理、便捷的业务逻辑嵌入;两者配合:Nginx 做外层通用入口,Gateway 做内层微服务专属网关,兼顾性能和微服务能力。
2025-09-24 11:07:06
1255
原创 堆比栈访问快的原因
分配 / 释放靠 “指针移动”,无复杂计算;访问集中在栈顶,且内存连续,CPU 缓存命中率高;无需 GC 参与,无额外开销。而堆的模型更 “复杂”:动态分配、离散存储、依赖 GC,这些特性决定了其访问速度必然慢于栈。也正因如此,JVM 才会将 “临时、小量、短期” 的数据(局部变量、方法调用)放在栈中,将 “长期、大量、共享” 的数据(对象实例)放在堆中 —— 两者分工,兼顾效率与灵活性。
2025-09-23 17:07:47
553
原创 G1垃圾回收器的回收过程
G1 的执行过程以 “并发标记 + 筛选回收” 为核心,通过四阶段协作实现高效垃圾回收:前两阶段(初始标记、并发标记)完成存活对象识别,后两阶段(最终标记、筛选回收)完成垃圾清理与内存整理,同时通过 STW 控制和区域优先级策略,在大堆场景下实现了延迟与吞吐量的平衡。
2025-09-23 17:00:25
400
原创 CMS(Concurrent Mark Sweep)垃圾回收器选择标记 - 清除(Mark-Sweep) 算法原因
优点:避免移动对象,支持 “并发标记” 和 “并发清除”,将 STW 时间压缩到极致,满足响应时间敏感场景;缺点:产生内存碎片,可能导致频繁的 Full GC(整理碎片时停顿更长)。这也解释了为什么 CMS 适合 “短期低延迟优先” 的场景(如 Web 服务),而不适合 “长期运行且内存碎片敏感” 的场景(如大数据处理)。
2025-09-23 16:22:28
922
原创 thenRun() 和 thenRunAsync() 的区别
方法执行线程来源适用场景thenRun()上一个任务的线程或当前调用线程延续任务逻辑简单,无需额外线程时ForkJoinPool 公共线程池延续任务可能耗时,需避免阻塞上一个任务实际开发中,若延续任务较短,可使用thenRun()减少线程切换开销;若延续任务可能耗时,建议用避免阻塞原有线程。
2025-09-23 15:26:49
307
原创 ConcurrentHashMap分段锁
数量(默认 16),该参数决定了初始的段数范围。数量一旦初始化后不可动态修改(扩容时仅增加每个。1.7 及之前版本的核心同步机制,锁对象是。与 JDK 1.8 “桶级锁” 的区别。在 JDK 1.7 中,数组),锁仅作用于当前。内部管理一部分哈希桶(
2025-09-23 14:26:22
339
原创 AT模式写隔离
不依赖数据库锁的长持有:数据库锁仅在本地事务执行时短暂持有,提交后立即释放,不影响数据库并发。靠全局锁做 “最终把关”:通过 Seata 层面的全局锁,控制同一条数据的多个全局事务的执行顺序,确保只有先执行的事务全局结果确定后,后执行的事务才能完成,避免脏写。效率与隔离的平衡:既解决了 XA 模式 “数据库锁长持有导致的效率低”,又通过全局锁保证了写隔离的正确性。
2025-09-17 09:58:23
498
原创 >>(带符号右移)和 >>>(无符号右移)的区别
操作符高位填充内容对负数的影响典型用途>>补符号位(0 或 1)保持负数性质(结果仍为负数)有符号数的除法(/2ⁿ)>>>始终补 0结果变为正数(符号位被覆盖)无符号数的位运算处理。
2025-09-04 16:29:40
707
原创 redisTemplate.opsForValue().bitField() 方法返回 List<Long> 而非单个 Long的原因
BITFIELD命令支持多子命令,因此返回结果是集合类型。Spring Data Redis 为了兼容多命令场景,统一返回List<Long>。单个子命令时,取列表第一个元素即可得到目标Long值。这种设计保证了 API 的一致性,无论执行多少个子命令,返回类型都保持统一。
2025-09-04 16:12:21
483
原创 ThreadLocal为什么会发生内存泄露
虽然一个 实例只能存储一个值(每个线程一份),但内存泄漏的风险不是来自“存多个数据”,而是来自“长期持有不再需要的数据引用”,尤其是在使用线程池的场景下。我们来一步步拆解这个问题:你说得对,每个 实例在每个线程中只能关联一个 类型的值。例如:所以,单个 不会“堆积”多个值。问题的关键在于 线程的生命周期 和 的内部结构。会发生什么?这就是 内存泄漏:本应被释放的对象,因为被意外持有引用而无法回收。你可能会问:不是 key 是弱引用吗?那不是会自动清理吗?是的, 实例作为 key 是弱引
2025-08-27 23:27:28
785
原创 ThreadLocal中为什么key要设置为弱引用,value设置为强引用
项目引用类型原因key (实例)弱引用避免实例无法被回收,导致内存泄漏value (本地变量)强引用保证只要线程需要,就能访问到数据注意:弱引用 key 只是缓解了内存泄漏问题,真正防止内存泄漏的关键是开发者主动调用remove()方法。所以,的设计是“尽力而为”的内存管理策略:通过弱引用减少泄漏风险,但仍需开发者配合清理。
2025-08-27 23:25:30
619
原创 Redisson看门狗策略
Redisson 看门狗通过 “自动续期” 机制,完美解决了分布式锁 “过期时间设置难题”,确保锁在业务完成前不会提前释放,同时避免了死锁风险。无需手动估算过期时间,自动适配业务执行时长,是分布式锁的最佳实践之一。
2025-08-26 22:51:50
829
原创 Spring中第三级缓存的作用
第一级缓存(singletonObjects):存放完全初始化完成的单例 Bean(可以直接使用的最终实例)。第二级缓存(earlySingletonObjects):存放提前暴露的早期实例(未完全初始化,但已实例化的原始对象或代理对象)。第三级缓存(singletonFactories):存放Bean 的工厂对象(ObjectFactory),用于在需要时生成 Bean 的早期引用(可能是原始对象,也可能是 AOP 代理对象)。第三级缓存(singletonFactories)的核心作用。
2025-08-25 22:35:14
1307
原创 Spring框架中单例Bean是否是线程安全的
Spring 单例 Bean 的线程安全性取决于 Bean 是否包含共享可变状态:无状态 Bean 线程安全,有状态 Bean 线程不安全。Spring 不直接保证线程安全,需要开发者根据业务场景选择合适的同步策略(如锁、、原子类等)。最佳实践:尽量设计无状态的单例 Bean(如 Controller、Service、Repository 通常是无状态的),从根源上避免线程安全问题。
2025-08-25 22:03:29
1029
原创 串行化和可重复读的区别
串行化是SQL 标准中最高的事务隔离级别强制所有事务按 “串行顺序” 执行(而非并发执行),即一个事务完全结束后,另一个事务才能开始。这种 “排队执行” 的方式从根本上避免了所有并发冲突,是唯一能解决脏读、不可重复读、幻读三大问题的隔离级别。串行化是最高隔离级别,通过强制事务串行执行 + 严格锁定,解决所有并发问题(包括幻读),但牺牲了并发性能;可重复读(标准)的核心是通过 MVCC 保证 “单行版本一致”,解决不可重复读,但因无法阻止 “范围间隙的新行插入”,故无法解决幻读;
2025-08-25 21:19:22
710
原创 CMS中写屏障和增量更新
写屏障:是拦截引用修改的 “钩子”,让回收器感知到对象引用的变化。增量更新:是利用写屏障实现的策略,通过将 “新增引用白色对象的黑色对象” 重新标记为灰色,确保白色对象能被重新遍历和标记。两者配合解决了并发标记阶段的漏标问题,是 CMS 等并发垃圾回收器能正确工作的核心保障。
2025-08-23 21:50:21
530
原创 三色标记中例子说明
D 从始至终没有被任何 “可达路径” 覆盖,因此始终保持白色(未被标记)。D 的初始状态D 是一个孤立对象(没有任何 GC Roots 或存活对象引用它,即D → E这个引用链本身不被 GC Roots 可达)。标记过程中从未被遍历没有任何灰色对象会遍历到 D(D 没有被任何存活对象引用);写屏障也不会处理 D(因为没有存活对象引用 D,不会触发 “新增引用到 D” 的操作)。因此,D 始终保持初始的白色,标记结束后被判定为垃圾。
2025-08-23 21:33:01
441
原创 CMS三色标记
三色标记是 CMS 并发标记的核心算法,通过白、灰、黑三色追踪对象存活状态,实现高效的并发标记。漏标问题通过 “写屏障 + 增量更新” 解决:当黑色对象引用白色对象时,强制将黑色对象变回灰色,确保子对象被重新标记。三色标记的优势:允许应用线程与回收线程并发执行,大幅减少 STW 时间,适合低延迟场景(如 Web 服务)。这种机制平衡了垃圾回收的准确性和应用的可用性,是并发垃圾回收器的关键技术。
2025-08-23 21:19:07
718
原创 并发垃圾回收器
并发垃圾回收的执行流程围绕 “标记存活对象→清除垃圾” 展开,通过将耗时的标记和清除阶段与应用线程并发执行,仅在必要时短暂暂停应用,实现低停顿目标。其核心是平衡回收效率与应用可用性,典型代表如 CMS(侧重低延迟)和 G1(兼顾延迟与吞吐量)。
2025-08-23 21:12:17
872
原创 并发清除阶段详细
问题是否存在原因 / 解决机制产生新垃圾(浮动垃圾)是应用线程与回收线程并发执行,新垃圾只能等到下一次 GC 处理误清除存活对象否通过写屏障跟踪引用修改,强制保护存活对象,确保未标记的存活对象不会被误删本质上,并发清除阶段的设计是 “牺牲部分内存效率(容忍浮动垃圾),换取应用低停顿,同时通过写屏障确保内存安全这也是所有并发垃圾回收器(包括 CMS、G1)的核心权衡逻辑 —— 既要让应用少停顿,又要绝对避免内存安全问题。
2025-08-23 20:21:45
546
原创 指令重排的原因
指令重排是编译器和 CPU 的性能优化手段,单线程下无害,但多线程下可能破坏数据一致性。理解指令重排的风险,是编写线程安全代码的关键(例如用volatile禁止重排,或用同步机制保证顺序)。
2025-08-23 17:40:43
434
原创 自旋锁的过程
自旋获取锁的核心是 “循环重试而非立即阻塞”,通过消耗少量 CPU 时间换取线程状态切换的开销。它是 JVM 轻量级锁的实现基础,在并发程度低、锁持有时间短的场景下能显著提升性能,但需避免在激烈竞争或长耗时同步块中使用。
2025-08-23 13:48:41
421
原创 偏向锁→轻量级锁→重量级锁的介绍
偏向锁:单线程无竞争,通过 “记住线程 ID” 避免加锁开销。轻量级锁:少量线程交替竞争,通过 CAS 自旋减少阻塞。重量级锁:多线程激烈竞争,通过操作系统互斥量保证同步,牺牲性能换稳定性。JVM 通过这种 “按需升级” 的机制,在不同并发场景下平衡了同步安全性和性能,是从 “重量级锁” 优化为高效同步机制的核心原因。
2025-08-23 11:34:52
1086
原创 Static关键字的详解
static定义共享数据(静态变量);实现工具方法(静态方法);执行类初始化逻辑(静态代码块);定义独立于外部类实例的内部类(静态内部类)。合理使用static可以简化代码、提高效率,但需注意其对代码灵活性和线程安全的影响。
2025-08-22 23:08:04
533
原创 线程池的执行流程
线程池的执行流程本质是 “优先使用核心线程→再用队列缓冲→最后创建临时线程→超出则拒绝” 的资源分配策略,通过这种分层处理,既保证了任务的高效执行,又避免了线程无限制创建导致的系统资源耗尽问题。理解这一流程是合理配置线程池参数的基础。
2025-08-22 22:57:08
622
原创 网络请求密集型和CPU密集型场景下,线程池参数的设置
场景核心线程数(corePoolSize)最大线程数(maximumPoolSize)队列(workQueue)核心思路CPU 密集型CPU 核心数 或 CPU 核心数 + 1等于核心线程数大容量有界队列减少 CPU 上下文切换,提高计算效率网络请求密集型CPU 核心数2 ~ CPU 核心数4核心线程数的 1.5~2 倍小容量有界队列利用 IO 等待时间,增加并发处理能力实际调优建议。
2025-08-22 22:54:44
677
原创 依赖注入的理解
依赖注入(Dependency Injection,简称 DI)是面向对象编程中,核心是 “”,从而降低代码耦合度,提高灵活性和可测试性。
2025-08-22 22:01:28
1020
原创 ofType和javaType的区别
属性作用对象适用场景示例javaType属性本身的类型所有类型(简单类型、对象、集合)声明address是对象;声明orders是List集合。ofType集合中元素的类型仅集合类型(ListSet等)声明List中元素是Order对象。
2025-08-22 21:15:53
523
原创 索引对查询(SELECT)和写入(UPDATE/INSERT)效率的影响
索引对查询友好:通过预先构建的有序结构,减少查询时的扫描范围,提高SELECT效率。索引对写入不友好:写入时需同步维护索引结构(插入、删除、平衡),增加额外的 IO 和计算开销,降低UPDATEINSERT效率。不为不常用的查询建索引,不为频繁写入的字段建过多索引,避免 “为了查询快一点,让写入慢很多”
2025-08-21 23:02:11
488
原创 ACID 和 CAP的区分
ACID 是单机数据库事务原子性(Atomicity):事务是不可分割的最小单位,要么全部执行成功,要么全部失败回滚(如转账操作要么双方余额同时更新,要么都不更新)。一致性(Consistency):事务执行前后,数据必须从一个合法状态转换到另一个合法状态,符合业务规则(如转账后双方总余额不变)。隔离性(Isolation):多个事务并发执行时,彼此的操作互不干扰,避免脏读、不可重复读等问题(通过隔离级别控制,如读已提交、可重复读)。持久性(Durability)
2025-08-21 22:30:29
663
原创 Class.forName() 和 ClassLoader 的区别
特性核心功能加载类 + 执行静态初始化(默认)仅加载类,不执行静态初始化底层依赖内部调用 ClassLoader,但多了初始化步骤类加载的核心工具,仅负责加载字节码典型场景加载数据库驱动、需要立即初始化的类动态加载类信息、延迟初始化场景是否执行静态代码块是两者最直观的区别。
2025-08-21 11:36:53
483
原创 可作为GC Root的对象类型有什么?
正在使用的局部变量(栈中)、静态变量(方法区)、常量(方法区);活跃线程、JNI 引用、被同步锁持有的对象等。垃圾回收器通过这些根节点,逐层遍历引用链,最终确定哪些对象可以被安全回收。
2025-08-21 10:14:43
647
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅