- 博客(63)
- 收藏
- 关注
原创 【多线程篇14】:Java内存模型(JMM)与JVM内存区域的详细区分理解
摘要: JVM内存区域与Java内存模型(JMM)本质不同:前者是JVM规范定义的内存空间划分(堆、栈、方法区等),关注数据存储位置及回收;后者是并发编程抽象规范,通过主内存/工作内存模型定义多线程共享变量的可见性、有序性规则。JVM内存区域提供物理存储,JMM制定并发访问逻辑,二者协同保障Java程序的高效与线程安全。核心差异在于前者解决数据存哪里,后者解决如何安全访问
2025-07-18 08:51:59
532
原创 【多线程篇13】:Java内存模型JMM必会详解
Java内存模型(JMM)是Java并发编程的核心规范,定义了线程间共享变量的可见性、有序性和原子性规则。JMM通过抽象的主内存和工作内存概念,屏蔽底层硬件差异,解决多线程环境下的数据一致性问题。与JVM内存区域不同,JMM是语言层面的并发规范,而后者是运行时数据存储的物理划分。JMM的核心价值在于为开发者提供跨平台的一致内存访问保证,通过volatile、synchronized等机制实现线程安全。理解JMM对编写正确高效的并发程序至关重要。
2025-07-18 00:31:14
710
原创 【多线程篇12】:一文看懂ReentrantReadWriteLock核心
摘要: ReentrantReadWriteLock是JDK提供的可重入读写锁,通过读写分离机制提升并发性能。其核心特点是读操作共享(允许多线程并发读),写操作独占(互斥)。内部包含读锁(共享锁)和写锁(独占锁),支持公平/非公平模式,默认非公平锁以提高吞吐量。该锁支持锁降级(写锁→读锁)但不支持升级(读锁→写锁),最适合"读多写少"场景,能显著提升系统并发性能。相比普通排他锁,其核心优势在于实现"读读不互斥"的并发控制。
2025-07-17 09:38:57
464
原创 【langchain4j篇02】:配置流式响应及高级API的使用详解
本文介绍了使用LangChain4j高级API实现流式响应聊天的技术方案。首先通过添加langchain4j-spring-boot-starter和langchain4j-reactor依赖,配置application.yml中的流式聊天模型参数。然后创建带有@AiService注解的接口DemoService,定义返回Flux<String>的chat方法实现流式响应。在Controller中注入该接口即可直接使用,无需实例化对象。通过配置日志等级可查看流式响应过程,其原理是框架通过动态代理
2025-07-17 08:15:00
1127
原创 【多线程篇11】:关于sychronized锁升级精简小结
Java的synchronized采用动态锁升级机制优化性能:初始为偏向锁(单线程访问,记录线程ID);多线程交替访问升级为轻量级锁(CAS操作,自旋尝试);高并发时转为重量级锁(基于操作系统互斥量)。锁升级流程为:无锁→偏向锁→轻量级锁→重量级锁,特殊情况下会降级。该机制根据竞争强度自动选择最优锁策略,平衡性能与线程安全。
2025-07-16 10:19:03
287
原创 【langchain4j篇01】:5分钟上手langchain4j 1.1.0(SpringBoot整合使用)
本文介绍了快速上手 langchain4j 最新版 的步骤。首先需准备API密钥,创建基于JDK17的项目并导入web依赖与langchain4j的低级API起步依赖。在application.yml中配置百炼平台baseUrl、API密钥、模型名等信息。之后创建Controller,注入默认的OpenAiChatModel,编写接口实现阻塞式聊天功能。配置打印日志后,可在控制台查看请求响应过程,从而快速使用langchain4j调用大模型。
2025-07-16 09:20:30
1189
原创 【多线程篇10】:详解java乐观锁的基本实现方式及其与悲观锁的对比
本文对比了多线程编程中的悲观锁与乐观锁两种并发控制策略。悲观锁(如Java的synchronized)假设竞争总会发生,先加锁再操作,确保线程安全但性能开销较大;乐观锁(如CAS原子类)假设冲突概率低,不加锁直接操作,仅在提交时检测冲突,适用于读多写少场景。文章详细介绍了乐观锁的三种实现方式(原子类、版本号、时间戳),并提供了选择建议:悲观锁适合高并发写入,乐观锁适合低冲突场景。最终选择取决于具体应用场景的性能需求和冲突概率。
2025-07-14 08:54:02
1144
原创 【多线程篇09】:一文看懂CAS技术与乐观锁思想
CAS(Compare-And-Swap)是一种硬件支持的原子操作,采用乐观锁策略实现无锁并发。它通过比较内存值(V)与预期值(A),仅在匹配时更新为新值(B),否则重试(自旋)。Java中通过Unsafe类和原子类(如AtomicInteger)封装CAS操作。尽管CAS高效,但存在三大问题:ABA问题(可通过AtomicStampedReference解决)、高并发时自旋开销大,以及仅支持单变量原子操作。CAS适用于低中并发场景,是高性能并发框架的基础技术。
2025-07-14 08:15:00
830
原创 关于langchain4j的文档官网的一个版本问题
LangChain4j提供了中英文两套文档(docs.langchain4j.dev/英文版和docs.langchain4j.info/中文版),当前最新版本为1.1.0-beta7。但中文文档中easyRAG的依赖版本存在错误,若使用1.0.0-beta3会导致EmbeddingStoreIngestor构建时出现文本分割器构造错误。建议使用英文文档获取更准确的信息,其中还包含中文版缺失的知识点搜索功能
2025-07-13 11:56:27
193
原创 【多线程篇08】:详解synchronized锁和ReentrantLock锁
摘要:本文对比了Java中两种可重入锁的实现——synchronized和ReentrantLock,从五个维度分析其差异:1) API层面,synchronized是隐式锁,由JVM管理;ReentrantLock是显式锁,需手动操作。2) 公平性,synchronized仅支持非公平锁,ReentrantLock可配置公平/非公平。3) 中断响应,synchronized不可中断,ReentrantLock支持中断锁获取。4) 功能丰富性,ReentrantLock提供tryLock和Condition
2025-07-13 09:27:33
656
原创 【多线程篇07】:一文看懂synchronized之外的的线程同步方案
摘要: Java并发编程中,synchronized虽易用但功能有限,JUC包提供了更强大的工具: ReentrantLock:显式锁,支持可中断、超时获取及公平锁,需手动释放,适合复杂同步场景。 volatile:仅保证变量可见性,适用于状态标记或“一写多读”,不保证原子性。 原子类(如AtomicInteger):基于CAS实现无锁线程安全操作,性能优异,适合计数器等单变量原子更新。 选择建议:简单场景用synchronized,高级需求用ReentrantLock,状态标记选volatile,单变量原
2025-07-13 09:00:23
1073
原创 【多线程篇06】:详解wait()和sleep()方法的区别对比
摘要: wait()和sleep()都能暂停线程执行,但机制和用途不同。 锁处理:wait()会释放持有的锁,而sleep()不会; 调用前提:wait()必须在同步代码块中调用,sleep()无限制; 唤醒方式:wait()需外部通知或超时,sleep()自动唤醒或被中断; 归属类:wait()属于Object类,用于线程间协作;sleep()属于Thread类,控制线程自身行为。 共同点:均会抛出InterruptedException,需处理中断。核心区别在于锁的释放与线程协作机制。
2025-07-12 13:33:50
510
原创 【多线程篇05】:详解interrupt()方法中断线程的机制
Java线程中断机制解析摘要: 线程中断是Java中的一种协作式信号机制,调用interrupt()仅设置线程的中断标志位,并不会强制终止线程。运行中的线程需通过isInterrupted()主动检查状态,而处于阻塞状态的线程(如sleep/wait时)被中断会立即抛出InterruptedException并清除中断标志。关键注意点在于:1)中断仅作为信号,线程需自行处理中断逻辑;2)捕获InterruptedException后应恢复中断状态;3)不同线程状态对中断的响应方式不同。该机制要求线程间协作,
2025-07-12 11:12:24
1095
原创 leetcode106深度解析:从中序与后序遍历序列构造二叉树
本文探讨如何从中序与后序遍历序列重构二叉树。核心思路是利用后序遍历末尾元素确定根节点,再用中序遍历划分左右子树范围。通过递归处理左、右子树对应的子序列完成构建。具体步骤包括:1) 后序末尾找根节点;2) 中序定位根节点划分左右子树;3) 根据左子树长度划分后序序列;4) 递归构建左右子树。代码实现采用哈希表优化查找效率,时间复杂度O(N),空间复杂度O(N)。与LC105前序+中序构建相比,主要区别在于根节点定位方式(后序末尾 vs 前序开头)和子序列划分逻辑。
2025-07-11 22:27:51
1009
原创 leetcode105深度解析:从前序与中序遍历序列构造二叉树
本文讲解如何通过前序遍历和中序遍历序列重建二叉树。核心思路是利用前序确定根节点,中序划分左右子树,通过递归解决子问题。具体步骤包括:1)前序首元素为根节点;2)在中序中找到根节点位置划分左右子树;3)根据子树节点数量划分前序序列;4)递归构建左右子树。代码实现中通过HashMap优化查找效率,使时间复杂度降为O(N),空间复杂度为O(N)。关键点在于区间定义和递归终止条件的处理。
2025-07-11 22:24:51
712
原创 【多线程篇04】:synchronized应用与面向对象视角下的锁机制
本文从面向对象视角解析Java中synchronized关键字的三种应用场景:实例方法同步锁住当前对象(this),静态方法同步锁住类对象(ClassName.class),以及同步代码块可指定任意对象作为锁。实例方法确保同一对象实例的同步方法互斥,静态方法实现类级别的全局互斥,而同步代码块提供更细粒度的锁控制。理解不同场景的锁对象选择是避免并发问题的关键。
2025-07-10 09:22:43
1069
原创 【多线程篇03】:一篇看懂线程的6种状态
本文详细解析了Java线程的六种状态及其转换机制,基于JDK Thread.State枚举定义。线程状态包括:NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(无限等待)、TIMED_WAITING(限时等待)和TERMINATED(终止)。关键转换路径涵盖:NEW通过start()进入RUNNABLE;RUNNABLE与BLOCKED状态在锁竞争时的相互转换;RUNNABLE与WAITING/TIMED_WAITING状态在wait/notify机制下的切换……
2025-07-08 18:52:58
1418
原创 【多线程篇02】:一文速懂并发与并行
并发与并行的核心区别在于是否真正同时执行任务。并发(Concurrency)指宏观上多个任务同时推进,但微观上单核CPU通过快速切换执行,任意时刻仅处理一个任务;并行(Parallelism)则需要多核CPU支持,多个任务能物理上同时执行。二者的关系在于:并发是并行的基础(程序需先支持并发才可能并行),但并发不一定并行(单核CPU仅能并发),而并行必然是并发。简言之,并发应对多任务(dealing with),并行执行多任务(doing)
2025-07-07 08:30:00
756
原创 【多线程篇01】:一文速懂线程和进程的区别
进程和线程是操作系统的核心概念。进程是程序的一次执行实例,拥有独立的内存空间和系统资源,是资源分配的基本单位;线程则是进程内的执行单元,共享进程资源但拥有独立的栈和寄存器,是CPU调度的基本单位。进程间隔离性强但开销大,线程开销小但需注意同步问题。线程的引入提升了程序并发性和响应速度,适用于需要频繁创建销毁的场景。两者在资源分配、独立性、开销和通信方式等方面存在显著差异。
2025-07-07 08:15:00
230
原创 【集合篇04】:HashMap扩容机制,resize()源码解读
本文分析了HashMap的扩容机制,重点解析了resize()方法的实现原理。扩容触发于初始化或元素数量超过阈值时,主要分为容量计算和数据迁移两部分。容量计算处理三种情况:正常扩容、指定初始容量和默认初始化。数据迁移时,JDK1.8优化了链表处理,通过(e.hash & oldCap)判断元素去向,将链表拆分为低位(原位置)和高位(原索引+老容量)两部分,避免了JDK1.7中重算哈希的开销。红黑树则通过split()方法处理,可能退化为链表。这种设计保证了HashMap的高效性。
2025-07-06 12:11:19
990
原创 证明:a%b == a&(b-1)
摘要:当b为2的整数次幂时,a%b等价于a&(b-1)。证明基于二进制分析:b-1形成低位掩码,保留a的低n位,而a%b的结果正是a的低n位数值。例如21%16=5,21&15=5,验证了该等式。这种位运算优化在底层编程中被广泛使用,可显著提升计算效率。
2025-07-06 10:42:50
593
原创 【集合篇02】:深入理解HashMap原理、冲突与优化
HashMap底层采用数组+链表/红黑树结构,通过哈希函数映射键到数组下标。当发生哈希冲突时,使用链表法存储相同哈希值的键值对。JDK1.8优化引入红黑树,当链表长度超过8且数组长度超过64时,链表转为红黑树,将时间复杂度从O(n)降为O(logn),既提升性能又防止DDoS攻击。基本操作put/get通过计算哈希值定位数组下标,再遍历链表或红黑树完成。在理想情况下,这些操作的时间复杂度为O(1),冲突严重时退化为O(n)或优化为O(logn)。
2025-07-06 09:00:00
515
原创 【集合篇03】:源码剖析HashMap实现原理
本文深入解析了HashMap的核心实现原理。首先介绍了其底层数据结构为哈希表,JDK1.8采用数组+链表/红黑树实现。重点剖析了put方法的执行流程:计算哈希值、确定数组下标、处理哈希冲突(包括覆盖值、链表追加或树化)、检查树化条件(链表长度≥8且数组长度≥64时转为红黑树)和扩容机制(负载因子0.75)。对比了JDK1.7和1.8的区别:1.8引入红黑树优化性能、采用尾插法代替头插法避免死循环、优化哈希计算和扩容逻辑。
2025-07-06 09:00:00
972
原创 【集合篇01】:ArrayList和LinkedList的详细对比
ArrayList与LinkedList的底层结构差异显著:前者基于动态数组,支持O(1)随机访问但插入删除需移动元素;后者采用双向链表,插入删除效率高(O(1)头尾操作)但查询需遍历(O(n))。内存方面,ArrayList更紧凑,LinkedList因存储指针占用更多空间。两者均非线程安全,可通过synchronizedList实现线程安全。选择依据:频繁随机访问选ArrayList,频繁插入删除选LinkedList。
2025-07-06 08:45:00
909
原创 【Spring篇10】:制作自己的spring-boot-starter依赖2
本文介绍了Spring Boot Starter的概念与制作流程。Starter是Spring Boot生态中的核心组件,通过打包依赖、配置和自动装配逻辑,简化开发者的使用。文章详细讲解了制作标准流程:创建项目结构、编写配置类、使用注解、注册配置和打包发布。并以"Hello World" Starter为例,展示了如何实现一个包含属性配置、服务类和自动配置的完整Starter。最后给出了命名规范和条件注解等最佳实践建议,帮助开发者创建规范的Spring Boot Starter模块。
2025-07-04 09:00:00
989
原创 【Spring篇09】:制作自己的spring-boot-starter依赖1
在企业级应用开发中,重复编写通用功能模块(如日志处理、RPC调用等)效率低下。Spring Boot Starter作为特殊依赖,可聚合相关依赖并提供自动化配置,让项目引入后自动获得所需功能。本文基于Spring Boot自动化装配原理,介绍自制Starter的方法。Starter本质是依赖聚合器和自动化配置提供者,其模块结构推荐分为入口模块“xxx-spring-boot-starter”和配置模块“xxx-spring-boot-autoconfigure”
2025-07-03 15:47:35
1167
原创 【Spring篇08】:理解自动装配,从spring.factories到.imports剖析
Spring Boot自动化装配简化了Spring应用配置,其核心机制围绕@EnableAutoConfiguration注解展开。早期版本通过META-INF/spring.factories文件注册配置类,2.7+版本引入.imports文件作为更规范的注册方式。AutoConfigurationImportSelector负责加载这些配置类,并结合条件注解(如@ConditionalOnClass)决定配置是否生效。该机制依赖运行时类路径发现配置,实现了智能化的自动装配,让开发者能够专注于业务逻辑开发
2025-07-03 15:38:08
1120
原创 【Spring篇07】:Spring生态核心注解速查指南
本文总结了Spring框架的核心注解分类:1) Spring基础注解包括组件声明(@Component)、依赖注入(@Autowired)、配置类(@Configuration)等;2) Spring MVC注解如@RequestMapping、@RequestBody等处理Web请求;3) Spring Boot特色注解如@SpringBootApplication自动配置、@RestController简化开发等。使用建议强调分层设计、构造器注入优先和配置优先级管理。这些注解构成了Spring生态的核心
2025-07-02 15:00:00
267
原创 【Mybatis篇01】:Mybatis执行流程 从配置文件到结果输出
MyBatis执行流程主要包括四个核心步骤:首先加载配置文件构建全局唯一的SqlSessionFactory;然后通过工厂创建轻量级的SqlSession会话;接着Executor执行器通过MappedStatement对象执行具体SQL操作;最后将数据库结果映射为Java对象返回。流程中还涉及两级缓存机制:一级缓存(SqlSession级别)默认开启,二级缓存(全局)需手动配置。最佳实践包括单例管理SqlSessionFactory、及时关闭SqlSession、合理使用缓存等。
2025-07-02 11:37:38
555
原创 【Spring篇06】:必会SpringBoot自动装配原理解析
Spring Boot自动装配原理核心是@EnableAutoConfiguration触发扫描META-INF/spring.factories文件,加载其中定义的配置类,并通过@ConditionalOnClass等条件注解基于运行时类路径决定是否启用。装配过程分为三层……
2025-07-02 10:41:31
714
原创 【Spring篇05】:Bean的循环依赖简析及其解决
Spring框架通过三级缓存机制解决循环依赖问题。当两个Bean相互依赖时,Spring会将未完成初始化的Bean引用存入三级缓存(singletonFactories),在需要时提供早期引用。具体流程包括:实例化Bean并存入三级缓存→发现依赖后暂停当前Bean初始化→通过三级缓存获取依赖Bean的早期引用→完成初始化后移入一级缓存。但该机制无法解决构造方法中的循环依赖,因为此时Bean尚未实例化,无法提供早期引用。对于构造方法循环依赖,建议调整设计,如改用Setter注入或@Autowired方式。
2025-07-02 10:40:35
848
原创 【Spring篇04】:Bean的生命周期简析
Spring Bean生命周期以控制反转(IoC)和依赖注入(DI)为核心,通过Aware接口、BeanPostProcessor等扩展点实现灵活控制。其流程可概括为:加载BeanDefinition后,经构造函数实例化、依赖注入,再依次触发Aware接口回调、BeanPostProcessor前置处理,执行初始化方法(如@PostConstruct标记的方法),接着进行BeanPostProcessor后置处理(常用于生成AOP代理),最终在容器关闭时执行销毁方法(如@PreDestroy标记的方法)。
2025-07-02 08:45:23
1036
原创 【Spring篇03】:@Transcational事务失效几种常见场景及原因简析
Spring事务失效通常因AOP代理机制被破坏导致,常见场景包括:1. 异常被捕获未抛出(默认只回滚RuntimeException);2. 检查异常未配置rollbackFor;3. 非public方法无法被代理;4. 同类内部方法调用(高频问题,this调用绕过代理);5. 传播行为配置不当。解决方案包括:正确处理异常、规范方法可见性、拆分服务类避免内部调用等。理解代理机制是排查事务问题的关键,需确保所有事务方法都通过Spring容器管理的代理对象调用。
2025-07-02 08:44:54
687
原创 【Spring篇02】:AOP与事务实现原理
Spring AOP通过环绕通知实现方法拦截控制,使用ProceedingJoinPoint处理目标方法执行前后逻辑,类比"动作替身"机制。切点表达式定义拦截规则,支持execution语法和注解匹配。事务管理基于AOP代理实现,@Transactional结合TransactionInterceptor完成事务创建、提交和回滚。生产实践中需注意注解位置、传播行为、性能优化和自调用问题。面试要点包括异常处理优先级、注解优先级和隔离级别设置等核心机制。
2025-07-01 16:49:10
947
原创 深度剖析:基于AOP、自定义注解与设计模式构建高度可定制的分布式锁解决方案
本文提出了一种基于Spring AOP和自定义注解的分布式锁解决方案,通过@MyLock注解实现声明式加锁。该方案采用策略模式封装不同锁获取策略(如快速失败、有限重试等),工厂模式支持多种锁类型(可重入锁、公平锁、读写锁),有效解决了传统分布式锁实现中代码侵入性强、重复代码多、不够灵活等问题。核心设计包括:1)@MyLock注解提供锁名称、等待时间、锁类型等配置项;2)MyLockType枚举定义支持的锁类型;3)MyLockStrategy枚举实现策略模式,处理获取锁失败的不同行为。该方案显著提升了代码可
2025-07-01 11:20:47
1781
原创 【Spring篇01】:Bean的线程安全问题总结
Spring框架中的单例Bean默认非线程安全,需开发者根据场景处理并发问题。核心解决方案包括:①优先设计无状态Bean(无成员变量);②使用ThreadLocal或并发工具类(如AtomicLong)管理线程级/共享状态;③避免滥用prototype作用域。典型案例表明,统计类服务推荐Atomic原子类,用户会话数据适用ThreadLocal。关键原则是:单例Bean的线程安全取决于设计,应避免可变状态,必要时采用最小化同步策略。
2025-07-01 09:58:57
1070
原创 AndroidStudio 中虚拟机连接宿主机(本机)服务
当安卓模拟器无法连接本地后端服务时,需将代码中的 localhost:8080 替换为主机实际IP地址。通过ipconfig命令查看主机的无线局域网适配器(WLAN)IPv4地址(如192.168.10.7),并在安卓代码中使用该IP。确保模拟器与主机处于同一Wi-Fi网络,同时检查防火墙是否拦截了8080端口,必要时开放端口权限以允许通信。
2025-06-28 17:34:28
126
原创 【SpringAI篇04】:基于 ChatMemory 查询聊天记录
在上文聊天记录持久化基础上,增加查询聊天记录功能,由于聊天记录基于 ChatMemory 接口存储,通过注入该接口并传入对话 ID,可调用其get(String conversationId)方法查询历史消息。示例中HistoryController通过@GetMapping映射接口,接收chatId参数并调用chatMemory.get(String.valueOf(chatId)),实现按会话 ID 查询对话历史,该功能依赖于此前配置的持久化存储方案(如 MySQL),可从数据库中读取已保存的对话记录。
2025-06-27 16:53:20
191
1
原创 【SpringAI篇03】:聊天记录持久化(仍保留上下文)
本文主要介绍在SpringAI框架中为聊天记忆功能添加持久化存储的实现过程。默认内存存储方案(InMemoryChatMemoryRepository)存在数据易丢失和消息数量受限的问题,通过引入MySQL持久化方案可解决:添加JDBC存储依赖,创建对话记忆表,配置数据源及Spring AI相关参数,注入JdbcChatMemoryRepository替换默认内存存储。测试表明,该方案实现了对话历史的数据库持久化,支持服务重启后读取历史记录及会话隔离。
2025-06-27 16:35:05
980
原创 【SpringAI篇02】:实现连续对话(上下文记忆功能+会话隔离)
在 Spring AI 中实现对话记忆功能,需先配置 ChatMemory。通过新建 MemConfig 配置类,利用 MessageWindowChatMemory.builder () 构建实例,设置 InMemoryChatMemoryRepository 存储对话,默认最大消息数 20 条,超过自动移除旧消息,实现基于窗口的对话记忆。接着在 ChatConfig 配置类中,为 ChatClient 添加 Advisor 增强功能。通过 defaultAdvisors 加入 SimpleLogger
2025-06-26 18:21:06
1005
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人