<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[彩虹地带]]></title><description><![CDATA[程序员学习过程中的思考总结]]></description><link>https://blog.csdn.net/Ray_Chan01</link><language>zh-cn</language><generator>https://blog.csdn.net/</generator><copyright><![CDATA[Copyright &copy; Ray_Chan01]]></copyright><item><title><![CDATA[同样是多路复用，epoll 凭啥让 Redis 跑得飞快？]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/161824879</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/161824879</guid><author>Ray_Chan01</author><pubDate>Tue, 09 Jun 2026 11:49:58 +0800</pubDate><description><![CDATA[本文介绍了Redis在Linux系统中采用epoll模型实现高性能网络通信的机制。相比select模型，epoll的核心优势在于：1）内核预先筛选有事件的fd，避免遍历所有fd；2）减少用户态与内核态间fd的拷贝次数；3）通过回调函数主动通知就绪fd；4）支持百万级并发连接而无硬性上限。这些特性使epoll成为Redis高吞吐量的关键支撑。]]></description><category></category></item><item><title><![CDATA[让我告诉你Kafka元数据都存了啥]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/149404938</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/149404938</guid><author>Ray_Chan01</author><pubDate>Wed, 16 Jul 2025 18:33:51 +0800</pubDate><description><![CDATA[metadataExpireMs，用于控制客户端缓存的元数据信息的有效期。在客户端向Kafka集群发送请求之前，元数据信息被认为有效的最长时间。默认值是300000毫秒，即5分钟。clusterResourceListeners，用于指定一组监听器，这些监听器会在客户端检测到Kafka集群资源发生变化时被触发。lastSuccessfulRefreshMs，用于记录上一次成功刷新元数据的时间戳（以毫秒为单位）。lastRefreshMs，这个变量记录了客户端最后一次成功刷新元数据的时间戳（以毫秒为单位）。]]></description><category></category></item><item><title><![CDATA[Kafka生产者的初始化]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/149180628</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/149180628</guid><author>Ray_Chan01</author><pubDate>Mon, 07 Jul 2025 20:02:30 +0800</pubDate><description><![CDATA[本文介绍了Kafka生产者配置关键参数及其作用：1）retry.backoff.ms控制重试间隔（默认100ms）；2）metadata.max.age.ms管理元数据刷新周期（默认5分钟）；3）max.request.size限制单个请求大小（默认1MB）；4）buffer.memory设置发送缓冲区（默认32MB）；5）compression.type选择消息压缩方式。这些参数优化了网络传输、集群负载和容错机制，合理配置可显著提升Kafka生产者的性能和可靠性。]]></description><category></category></item><item><title><![CDATA[你是怎么明确你们系统的qps是多少？如何架构系统负载每天几千万请求？]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/148253038</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/148253038</guid><author>Ray_Chan01</author><pubDate>Tue, 27 May 2025 16:11:32 +0800</pubDate><description><![CDATA[本文系统介绍了服务器性能指标的核心概念：QPS（每秒查询数）和TPS（每秒事务数），解析了两者的区别与联系，指出一个TPS可能包含多个QPS。同时阐述了响应时间（RT）、并发数、吞吐量等关键指标的计算方法和相互关系。文章还解释了PV、UV、DAU、MAU等用户行为指标，最后给出了通过二八定律估算服务器需求量的实用公式。这些指标共同构成了评估系统性能的完整体系，为系统容量规划提供了理论基础。]]></description><category></category></item><item><title><![CDATA[类变量、成员变量、局部变量分别存储在内存的什么地方？]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/147238801</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/147238801</guid><author>Ray_Chan01</author><pubDate>Tue, 15 Apr 2025 09:15:02 +0800</pubDate><description><![CDATA[修饰符修饰的变量，随着类的实例产生和销毁，是类实例的一部分由于是实例的一部分，在类初始化的时候，从运行时常量池取出直接引用或者值，与初始化的对象。在所在方法被调用时放入虚拟机栈的栈帧中，方法执行结束后从虚拟机栈中弹出。修饰符修饰，定义在方法外的变量，随着。局部变量是定义在类的方法中的变量，之前把静态变量存放于方法区，在。成员变量是定义在类中，但是没有。]]></description><category></category></item><item><title><![CDATA[JVM 的主要组成部分及其作用？]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/146166554</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/146166554</guid><author>Ray_Chan01</author><pubDate>Mon, 10 Mar 2025 23:41:43 +0800</pubDate><description><![CDATA[的一套指令集规范，并不能直接交给底层操作系统去执行，因此需要特定的命令解析器执行引擎（Execution Engine。文件中的二进制数据读入到内存中，将其放在运行时数据区的方法区内，然后在堆区创建一个 java.lang.Class。）再把字节码加载到内存中，将其放在运行时数据区（Runtime data area。将源代码编译成字节码文件，字节码文件的后缀名为。）的方法区内， 而字节码文件只是 JVM。其实可以一句话来解释：类的加载指的是将类的。），将字节码翻译成底层系统指令，再交由。]]></description><category></category></item><item><title><![CDATA[Spring事务核心流程分析]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/145927381</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/145927381</guid><author>Ray_Chan01</author><pubDate>Fri, 28 Feb 2025 14:06:11 +0800</pubDate><description><![CDATA[到这里，我们的 获取事务 接口完成了 数据库连接的创建 和 关闭自动提交（开启事务），将。处理提交，先处理保存点，然后处理新事务，如果不是新事务不会真正提交，要等外层是新事务的。如果是新事务的话，进行数据清除，线程的私有资源解绑，重置连接自动提交，隔离级别，是否只。此方法做清除连接相关操作，比如重置自动提交啊，只读属性啊，解绑数据源啊，释放连接啊，清。线程的私有资源解绑，重置连接自动提交，隔离级别，是否只读，释放。和线程的私有资源解绑，重置连接自动提交，隔离级别，是否只读，]]></description><category></category></item><item><title><![CDATA[面试官在问Spring是如何实现事务的，你这样回答]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/145906312</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/145906312</guid><author>Ray_Chan01</author><pubDate>Thu, 27 Feb 2025 15:51:49 +0800</pubDate><description><![CDATA[创作内容丰富的干货文章很费心力，感谢点过此文章的读者，点一个关注鼓励一下作者，激励他分享更多的精彩好文，谢谢大家！]]></description><category></category></item><item><title><![CDATA[详解：事务注解 @Transactional]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/145880557</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/145880557</guid><author>Ray_Chan01</author><pubDate>Wed, 26 Feb 2025 15:43:17 +0800</pubDate><description><![CDATA[，另外，配置类事务的传播行为支持当前事务，当前如果没有事务，那么会创建一个事。事务的传播规则是指在多个事务方法相互调用的情况下，事务应该如何进行传播和管理。属性用于指定事务的传播行为，它决定了当前方法执行时，如何处理已经存在的事务。属性用于指定事务的隔离级别，它决定了当前事务与其他事务之间的隔离程度。事务的创建也是有一定的规则，对于一个方法里已经存在的事务，支持当前事务，如果当前没有事务，就以非事务来执行。以非事务执行操作，如果当前存在事务，则当前事务挂。新建事务，如果当前存在事务，就把当前事务挂起。]]></description><category></category></item><item><title><![CDATA[大厂面试题：读过Spring源码吗？说说Spring事务是怎么实现的？]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/145852582</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/145852582</guid><author>Ray_Chan01</author><pubDate>Tue, 25 Feb 2025 15:00:30 +0800</pubDate><description><![CDATA[事务必须是一个原子的操作序列单元，事务中包含的各项操作在一次执行过程中，要么全部执行成功，要么全部不执行，任何一项失败，整个事务回滚，只有全部都执行成功，整个事务才算成功。即不同的事务并发操纵相同的数据时，每个事务都有各自完整的数据空间，即一个事务内部的操作及使用的数据对其他并发事务是隔离的，并发执行的各个事务之间不能相互干扰。指的是在一个事务内，最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不。数据库的默认隔离级别。在并发环境中，并发的事务是相互隔离的，一个事务的执行不能被其他事务干扰。]]></description><category></category></item><item><title><![CDATA[Spring Bean 初始化如何保证线程安全]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144121506</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144121506</guid><author>Ray_Chan01</author><pubDate>Thu, 28 Nov 2024 21:50:57 +0800</pubDate><description><![CDATA[已经被正确初始化了。并且这里的初始化不仅仅指构造函数中的内容，而是 Spring 语境下的初始化，还包括setter 注入，PostConstruct 初始化等。在 Spring Bean 的初始化中，我们通常不需要显式地指定某个字段是 volatile，是因为 Spring 有相关机制做了保证。于是，我们只要注入了某个 Bean，那么这个 Bean 的初始化的内容就是可见的，上例中，在。我们知道 Spring 默认创建的 Bean 是单例的，那么 Bean 中的字段需要声明成。的习惯，那是在作死吗？]]></description><category></category></item><item><title><![CDATA[良好的并发编程习惯之利用线程安全类]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144121294</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144121294</guid><author>Ray_Chan01</author><pubDate>Thu, 28 Nov 2024 21:43:38 +0800</pubDate><description><![CDATA[也因此，常见的并发需求通常也集中在对集合（collection）类的读写上。日常的线程安全问题通常会落在原始（ primitive）类型和集合（Collection）类，而使用对应的线程安全类通常就能直接解决问题。我们日常开发中的并发需求，通常用 JUC 中的类替换相应的原始类型或集合类，就可以达到线程安全。两种同步原语，在性能要求高的一些场景下，用它们来实现细粒度的同步会极大增加代码的复杂程度，性能也不好。虽然可能显而易见，要注意的是只有包装类提供的方法才保证是原子的，而里面存储的内容则没有。]]></description><category></category></item><item><title><![CDATA[良好的并发编程习惯之不可变（Immutability）]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144097084</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144097084</guid><author>Ray_Chan01</author><pubDate>Wed, 27 Nov 2024 23:30:06 +0800</pubDate><description><![CDATA[不可变对象在 Java 中主要需要解决的是“可见性”和“有序性”的问题，要保证线程看到对象时，对象已经是正确初始化的，而约定上的不可变并没有这个保证。理论上真正的不可变对象，还要求对象创建后其中的状态就不再修改，如果对象不提供任何修改内部状态的手段，我们就能百分百确定对象发布后是线程安全的。不可变对象的状态在构造函数中就唯一确定了，之后不接受任何的更改，因此编译器能对它做更可靠的优化，更容易保证它的线程安全性。当然没问题，这就是“约定” vs “机制”的问题了，约定技术上是可能被打破的，机制不会但代价高。]]></description><category></category></item><item><title><![CDATA[良好的并发编程习惯之封闭（Confinement）]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144097050</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144097050</guid><author>Ray_Chan01</author><pubDate>Wed, 27 Nov 2024 23:28:21 +0800</pubDate><description><![CDATA[例如有个 volatile 变量，在编写代码的时候，隐含实现了这样的约定：只有一个线程会“写”该变量，其它线程只会“读”操作。"Ad-hoc" 一般指“特别的、专门的、临时的”等，在编程的语境中一般指“具体情况具体分析”。要注意的是，由于需要为每个线程创建一个副本，如果初始化的代价比较高且经常性地创建新的线程，可能会有潜在的性能问题，虽然通常情况下不会成为问题。一般如果一个方法只依赖它的输入参数和方法内创建的局部变量，不依赖其它的全局的信息，则可以说这个方法是“无状态”的。的语义上就是“线程封闭”的。]]></description><category></category></item><item><title><![CDATA[常见线程安全问题之复合操作]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144071023</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144071023</guid><author>Ray_Chan01</author><pubDate>Tue, 26 Nov 2024 23:48:39 +0800</pubDate><description><![CDATA[通常原子类(如 AtomicReference) 对单个操作的原子性保证很方便，但复合操作本身需要加锁，这里再使用原子类就显得没必要了。从 TOCTOU 一节中我们知道，要解决这种竞争问题，需要把对状态的检查与使用都变成原子的，最简单的方式就是在方法上用。代码块保证原子性，在 ② 中用同样方法保证赋值的原子性。不过在本节我们要强调的是，即使每个操作本身是原子的，复合操作也不是原子的，这种情形有时候比较难一眼就认出来。都是原子的，只不过复合操作的问题是，即使每个操作都是原子的，操作整体也不是原子的。]]></description><category></category></item><item><title><![CDATA[常见线程安全问题之Double Checked Locking]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144070883</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144070883</guid><author>Ray_Chan01</author><pubDate>Tue, 26 Nov 2024 23:43:28 +0800</pubDate><description><![CDATA[最简单的解决方式是读操作也加锁，如果性能达不到要求，也可以像本节一样使用 volatile，但我个人不建议这么用，因为有太多细节需要考虑，可以使用 JUC 中的。问题不仅仅在于写的一方，即使 helper 被正确初始化并赋值，由于另一个线程所在的 CPU 可能会从缓存中读取 helper 的值，如果 helper 的新值还没有被更新到缓存中，则读取的值可能还是。因为 64 位的操作不是原子的，于是可能造成前后 32 位不是一起写入内存的，而另一个线程只读取先写入的 32 位，读到的结果不正确。]]></description><category></category></item><item><title><![CDATA[常见线程安全问题之TOCTOU]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144025440</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144025440</guid><author>Ray_Chan01</author><pubDate>Mon, 25 Nov 2024 13:47:45 +0800</pubDate><description><![CDATA[我们可以看到，TOCTOU 的主要问题在于状态的检查和状态的使用整体上不是原子的，而前面的章节中我们知道 Java 中最简单的实现原子性的方式是使用内置锁（intrinsic lock），即。TOCTOU 问题的根源是使用状态时，其实依赖了之前的状态检查结果，而在检查到使用的这段时间里，状态被其它线程/进程修改了，于是依赖的条件被打破，使得对状态的使用不再正确。是互斥锁，意味着即使初始化正确完成后，依然只有一个线程能执行代码，于是在高并发下性能不好，之后的章节中会介绍如何优化。Java 里最方便的是。]]></description><category></category></item><item><title><![CDATA[Happens Before]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/144025276</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/144025276</guid><author>Ray_Chan01</author><pubDate>Mon, 25 Nov 2024 13:38:43 +0800</pubDate><description><![CDATA[其它获取锁的线程会被阻塞，直到该锁被释放。本章中我们了解了只有“共享可变状态”的情形下，多线程间的先后顺序才会引发线程安全问题，之后列出了 Java 中的跨线程操作，最后学习了 Happens Before 的（非正式）的规则，以及 HB 规则如何帮助我们对程序运行结果做出推论。在执行时，会先拿到上锁对象的引用，然后尝试对该对象的监视器执行 lock 操作，得到锁后开始执行代码块里的操作，代码块执行结束后（不管是正常结束还是抛异常），会在同样的监视器上执行 unlock 操作释放锁。]]></description><category></category></item><item><title><![CDATA[残酷的现实]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/143967530</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/143967530</guid><author>Ray_Chan01</author><pubDate>Fri, 22 Nov 2024 11:37:40 +0800</pubDate><description><![CDATA[而这样做的目的，都是为了提高性能。事实上左边代码的效率远高于右边的代码，这是因为通常行的数据在内存里是连续排布的，按行遍历时，该行下一列元素的缓存命中率会比按列遍历时，该列一下个元素的命中率高很多，这能极大提高程序的效率（可能会高几十倍）。这是因为单线程程序的预期运行顺序和代码的编写顺序一样，编译器预先知道了各个操作的依赖关系，因此可以在不破坏依赖关系的前提下进行重排序，而在多线程的语境下，只看代码，编译器并没有办法推断出代码的依赖关系，无法知道一个线程里的 write 操作是不是一定要在另一个线程的。]]></description><category></category></item><item><title><![CDATA[理想的并发世界]]></title><link>https://blog.csdn.net/Ray_Chan01/article/details/143966811</link><guid>https://blog.csdn.net/Ray_Chan01/article/details/143966811</guid><author>Ray_Chan01</author><pubDate>Fri, 22 Nov 2024 11:25:27 +0800</pubDate><description><![CDATA[我们希望“同一时刻”，只有一个线程进入临界区(#6)，所以我们在 #6 之前写了很多同步的逻辑，如果程序执行能满足 Sequential Consistency，那么上面的算法就能满足，在任意时刻，线程 A/B 只有一个能进入临界区，执行 #6 中的代码（实际可能有多行）。我们需要和机器有个约定，这样当结果不符合预期时，我们好分辩是代码写错了，还是机器执行错了。考虑 CPU 多个核的执行顺序，多核的执行结果，相当于把每个核要执行的操作汇总排个序，在这个顺序里，要求每个核的操作依旧保持在单核内的相对顺序。]]></description><category></category></item></channel></rss>