<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[pngyul的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/PNGYUL</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; PNGYUL]]></copyright><item><title><![CDATA[后端微服务的 monorepo-like workspace 方案]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/161147630</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/161147630</guid><author>PNGYUL</author><pubDate>Sat, 16 May 2026 22:18:00 +0800</pubDate><description><![CDATA[可以理解为：类 monorepo 工作区或者  monorepo 风格的多仓库工作区它不是真正的 monorepo。一个 Git 仓库里面包含多个服务 / 模块 / 包一次 commit 可以同时修改多个模块CLAUDE.md.git/CLAUDE.md.git/CLAUDE.md.git/CLAUDE.md.git/CLAUDE.md这里每个服务都有自己的.git，所以它们仍然是独立仓库。claude一个根目录一个根 CLAUDE.md下面有多个服务目录。]]></description><category></category></item><item><title><![CDATA[Netty网络基础的通俗理解（网络&操作系统）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/134701436</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/134701436</guid><author>PNGYUL</author><pubDate>Sun, 17 Dec 2023 20:46:23 +0800</pubDate><description><![CDATA[Http 服务器是如何并发处理更多连接的？被讨论最多的 IO 模型？Reactor 与 Proactor的区别是什么？]]></description><category></category></item><item><title><![CDATA[JVM：安全点的细节实现]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/132196541</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/132196541</guid><author>PNGYUL</author><pubDate>Mon, 13 Nov 2023 22:13:48 +0800</pubDate><description><![CDATA[这部分内容主要是为了稍后介绍各款垃圾收集器时做前置知识铺垫，如果对这部分内容感到枯燥或者疑惑，可以先放下看，等后续遇到要使用它们的实际场景、实际问题时再结合问题，再回来阅读和理解。]]></description><category></category></item><item><title><![CDATA[JVM：如果是你，你如何解决跨代引用的问题？（记忆集和卡集）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/132196580</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/132196580</guid><author>PNGYUL</author><pubDate>Mon, 13 Nov 2023 22:12:54 +0800</pubDate><description><![CDATA[这部分内容主要是为了稍后介绍各款垃圾收集器时做前置知识铺垫，如果对这部分内容感到枯燥或者疑惑，可以先放下看，等后续遇到要使用它们的实际场景、实际问题时再结合问题，再回来阅读和理解。]]></description><category></category></item><item><title><![CDATA[JVM：卡表元素如何维护？（写屏障）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/132196615</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/132196615</guid><author>PNGYUL</author><pubDate>Mon, 13 Nov 2023 22:11:59 +0800</pubDate><description><![CDATA[编译优化带来并发的有序性问题）。伪共享是处理并发底层细节时一种经常需要考虑的问题，现代中央处理器的缓存系统中是以缓存行（Cache Line）为单位存储的，当多线程修改互相独立的变量时，如果这些变量恰好共享同一个缓存行，就会彼此影响（写回、无效化或者同步）而导致性能降低，这就是伪共享问题。另外，一旦收集器在写屏障中增加了更新卡表操作，无论更新的是不是老年代对新生代对象的引用，每次只要对引用进行更新，就会产生额外的开销，不过这个开销与Minor GC时扫描整个老年代的代价相比还是低得多的。]]></description><category></category></item><item><title><![CDATA[JVM：如何通俗的理解并发的可达性分析]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/132196637</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/132196637</guid><author>PNGYUL</author><pubDate>Wed, 04 Oct 2023 15:23:55 +0800</pubDate><description><![CDATA[比如在某一个GC roots 的对象图 已经标记完成了，此时用户线程再创建一个对象引用到前面已经编辑完成的对象图中，那么由于新插入的对象引用没有对标记到，那么再GC 时大概率就会被清除，这样的结果是致命的（类比下日常工作中的情况）。**原始快照（破坏的是第二个条件）：**当灰色对象要删除指向白色对象的引用关系时，就将这个要删除的引用记录下来，在并发扫描结束之后，再将这些记录过的引用关系中的灰色对象为根，重新扫描一次。另一种是把原本存活的对象错误标记为已消亡，这就是非常致命的后果了，程序肯定会因此发生错误。]]></description><category></category></item><item><title><![CDATA[JVM：根节点枚举的细节实现]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/132196518</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/132196518</guid><author>PNGYUL</author><pubDate>Tue, 19 Sep 2023 19:42:29 +0800</pubDate><description><![CDATA[这部分内容主要是为了稍后介绍各款垃圾收集器时做前置知识铺垫，如果对这部分内容感到枯燥或者疑惑，可以先放下看，等后续遇到要使用它们的实际场景、实际问题时再结合问题，再回来阅读和理解。]]></description><category></category></item><item><title><![CDATA[Zuul源码解析（二）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/130330418</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/130330418</guid><author>PNGYUL</author><pubDate>Sun, 23 Apr 2023 21:03:22 +0800</pubDate><description><![CDATA[ZuulProxyAutoConfiguration 如何触发？ZuulProxyAutoConfiguration  主要自动配置了那些东西组件？Zuul 又是怎么和 MVC 中的 DisPatcherServlet 联系起来的？]]></description><category></category></item><item><title><![CDATA[Zuul源码解析（一）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/130330209</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/130330209</guid><author>PNGYUL</author><pubDate>Sun, 23 Apr 2023 20:55:37 +0800</pubDate><description><![CDATA[Zuul 的核心流程、RouteLocator 、DiscoveryClientRouteLocator、Zuul 默认的 filter 等等源码解析]]></description><category></category></item><item><title><![CDATA[全链路日志追踪]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/130062642</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/130062642</guid><author>PNGYUL</author><pubDate>Mon, 10 Apr 2023 16:14:04 +0800</pubDate><description><![CDATA[全局追踪Id 错乱问题总结]]></description><category></category></item><item><title><![CDATA[并发设计模式（三）重要]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/124559100</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/124559100</guid><author>PNGYUL</author><pubDate>Thu, 05 May 2022 10:37:22 +0800</pubDate><description><![CDATA[三种最简单的分工模式
并发编程领域里，解决分工问题也有一系列的设计模式，比较常用的主要有 Thread-Per-Message 模式、Worker Thread 模式、生产者 - 消费者模式等等。
Thread-Per-Message 模式
在编程领域也有很多类似的需求，比如写一个 HTTP Server，很显然只能在主线程中接收请求，而不能处理 HTTP 请求，因为如果在主线程中处理 HTTP 请求的话，那同一时间只能处理一个请求，太慢了！怎么办呢？可以利用代办的思路，创建一个子线程，委托子线程去处理 H]]></description><category></category></item><item><title><![CDATA[并发设计模式（二）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/124558921</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/124558921</guid><author>PNGYUL</author><pubDate>Wed, 04 May 2022 19:35:41 +0800</pubDate><description><![CDATA[多线程版本的 If
Guarded Suspension模式
Guarded Suspension模式也被叫做Guarded Wait 模式，我也更倾向这种叫法。实际上，本质就是是一种等待唤醒机制的实现。
我觉得这个模式比较经典的一个应用是异步转同步（比如Dubbo 中 DefaultFuture 这个类也是采用的这种方式）
又比如用户通过浏览器发过来一个请求，而服务调用方A接受到这个请求，而这个请求需要请求其它服务提供方B的某个接口来返回结果。然而这个服务B暴露出来的交互方式并不是Http的方式，而是通过]]></description><category></category></item><item><title><![CDATA[并发设计模式（一）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/124558865</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/124558865</guid><author>PNGYUL</author><pubDate>Tue, 03 May 2022 18:18:03 +0800</pubDate><description><![CDATA[避免共享的设计模式
随便扯扯，刚开始我学到这里的时候，我有点茅舍顿开的感觉。怎么说呢，比如我现在呆的公司，有一个批量导出订单excel的功能。这个功能前员工已经实现了，当时我在阅读这部分代码的时候就觉得写这个代码的人很吊。他在代码中，利用多线程并发的批量请求数据，多线程封装符合导出格式的数据，而此时，他不是直接就写到excel中，而是先到一个阻塞队列中，然后另外开一个线程从队列中读数据写入到excel中（还有很多细节）。当时我就在想，他是怎么想到这种处理方式。原来这就是一种并发设计模式，就是下面会讲到的生产]]></description><category></category></item><item><title><![CDATA[技术人也要具备产品思维]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/124509421</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/124509421</guid><author>PNGYUL</author><pubDate>Sat, 30 Apr 2022 10:31:14 +0800</pubDate><description><![CDATA[##　写在前面
产品思维，这四个字，相信大家都不陌生。去年，我在一个付费圈子看到一篇文章，关于「到底什么是产品思维」，觉得写的非常好，至少比市面上一堆讲概念、故作高端的文章要通俗易懂。
产品思维可以说是人类最底层的能力，它可以应用于任何行业，现在结合我最近两三年的小白职场经历，也和大家聊聊这个东西。
##　技术思维＆产品思维
在说产品思维之前，首先想先和大家扯一下技术思维。
我们都是做技术的，所以我就拿程序员做个类比。程序员的思维我把他叫做技术思维，因为我都是程序员出身，所以我对技术思维是非常理解的，举个例]]></description><category></category></item><item><title><![CDATA[再扯 Spring 源码_白话文]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/123318262</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/123318262</guid><author>PNGYUL</author><pubDate>Thu, 10 Mar 2022 21:16:20 +0800</pubDate><description><![CDATA[在2021年之前，我在网上看过很多beam的 生命周期或者Aop相关源码的文章，并且自己简单实现了一个玩具级的Ioc 容器。所以如果说在面试过程中，面试官跟我扯beam的 生命周期或者Aop相关实现的话，我是非常的自信自己可以扯一大堆东西出来。但是如果再深入的话，我就很难说出来了。比如 @Bean 是在哪里实现的？@AutoWired 是如何实现的，核心是实现类是什么，Spring　的事件原理等等。
我真的很好奇，以至于今年年初，带着这些问题大致又刷了一篇。对ｂｅａｎＦａｃｔｏｒｙ甚至对Spring的核心思]]></description><category></category></item><item><title><![CDATA[记录：工作中遇到的两个问题]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/122197919</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/122197919</guid><author>PNGYUL</author><pubDate>Tue, 28 Dec 2021 17:14:34 +0800</pubDate><description><![CDATA[两个问题
前段时间遇到两个问题，对于现阶段的我来说，有点刺手
问题1： FeignClient的configuration被覆盖

我在调用 payment-service（其它部门提供的jar） 的 listPaymentOrderRela() 接口时报 json 解析错误：

这个报错的意思是说，你传过来的参数，不是 payment-service 的 listPaymentOrderRela()  接口想要的。
这时候我就觉得是 编码器 加载顺序的问题（DefaultEncoder 在公司公用的基础组]]></description><category></category></item><item><title><![CDATA[Java 为什么再造管程（六）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/121757921</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/121757921</guid><author>PNGYUL</author><pubDate>Mon, 06 Dec 2021 22:36:27 +0800</pubDate><description><![CDATA[文章导读：并发编程理论篇
（一）可见性，原子性，有序性的源头
（二）Java 如何解决可见性、有序性和原子性问题
（三）为什么存在等待 - 通知机制
（四）宏观角度看并发
（五）管程：并发编程的万能钥匙

在前面，我通过白话文的方式，简单介绍了并发编程的理论篇，感兴趣的可以看看前面的文章。接下来，简单聊聊并发编程工具篇。
Java 为什么再造管程
我们都知道，Java 语言本身提供的 synchronized 是管程的一种实现。另外，Java SDK 并发包通过 Lock 和 Condition 两个接口.]]></description><category></category></item><item><title><![CDATA[为什么存在等待 - 通知机制（三）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/121389843</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/121389843</guid><author>PNGYUL</author><pubDate>Wed, 17 Nov 2021 22:46:25 +0800</pubDate><description><![CDATA[细粒度锁的代价
上一章说到，用不同的锁对受保护资源进行精细化管理，使用细粒度锁可以提高并行度，是性能优化的一个重要手段。然而，天底下没有免费的午餐。使用细粒度锁是有代价的，这个代价就是可能会导致死锁。
// 经典的一个转账例子 ，会导致死锁
class Account {
  private int balance;
  // 转账
  void transfer(Account target, int amt){
    // 锁定转出账户
    synchronized(this) {        ]]></description><category></category></item><item><title><![CDATA[Java 如何解决可见性、有序性和原子性问题（二）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/121368145</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/121368145</guid><author>PNGYUL</author><pubDate>Tue, 16 Nov 2021 23:39:35 +0800</pubDate><description><![CDATA[在上一篇文章中，你可能已经知道了，导致可见性的原因是缓存，导致有序性的原因是编译优化，那解决可见性、有序性最直接的办法就是禁用缓存和编译优化，但是这样问题虽然解决了，我们程序的性能可就堪忧了。
合理的方案应该是按需禁用缓存以及编译优化。那么，如何做到“按需禁用”呢？对于并发程序，何时禁用缓存以及编译优化只有程序员知道，那所谓“按需禁用”其实就是指按照程序员的要求来禁用。所以，为了解决可见性和有序性问题，只需要提供给程序员按需禁用缓存和编译优化的方法即可。
Java 内存模型是个很复杂的规范，可以从不同的视角]]></description><category></category></item><item><title><![CDATA[可见性，原子性，有序性的源头（一）]]></title><link>https://blog.youkuaiyun.com/PNGYUL/article/details/121346310</link><guid>https://blog.youkuaiyun.com/PNGYUL/article/details/121346310</guid><author>PNGYUL</author><pubDate>Mon, 15 Nov 2021 23:52:18 +0800</pubDate><description><![CDATA[最近在学习极客时间的《并发编程实战》。我秉承着学习不仅是一个输入过程，输出也同等重要！下面大部分内容都是我在极客时间的笔记，但也有我的一些总结和见解。
并发程序幕后的故事
这些年，CPU、内存、I/O 设备都在不断迭代，不断朝着更快的方向努力。但是，在这个快速发展的过程中，有一个核心矛盾一直存在，就是这三者的速度差异。CPU 和内存的速度差异可以形象地描述为：CPU 是天上一天，内存是地上一年（假设 CPU 执行一条普通指令需要一天，那么 CPU 读写内存得等待一年的时间）。内存和 I/O 设备的速度差异就]]></description><category></category></item></channel></rss>