Mindblown: a blog about philosophy.
-
NAT 穿透是如何工作的:技术原理及企业级实践
https://arthurchiao.art/blog/how-nat-traversal-works-zh/#231-%E5%8F%8C%E5%90%91%E4%B8%BB%E5%8A%A8%E5%BB%BA%E8%BF%9E%E6%97%81%E8%B7%AF%E4%BF%A1%E9%81%93
-
blog地址推荐
https://wanglichao.com https://www.cnblogs.com/zhengyun_ustc https://developer.aliyun.com/article/25562
-
共享你自己的图片工具
在共享图片到互联网上并构建一个相册网站的过程中,有几个开源相册管理系统可以考虑使用。这些系统通常提供用户友好的界面和功能,用于管理和展示图片。 以下是一些流行的开源相册管理系统: 这些系统都提供了基本的相册管理功能,并且可以根据个人需求进行定制和扩展。你可以根据自己的喜好和需求选择合适的开源相册管理系统,用于共享你的图片到互联网上。
-
CompletableFuture的使用不当
对Completablefuture的使用不当,在异步请求中又嵌入了异步调用,当依赖服务变慢或请求量变大时,future会相互等待产生死锁。 在Java中,使用CompletableFuture时出现死锁的情况可能与不当的线程同步和锁定有关。下面是一个示例程序,演示了如何使用CompletableFuture造成死锁,并输出类似于您提供的死锁日志。 解释 解决方法 要避免死锁,可以重新设计代码,确保锁的获取顺序一致,或者尽量减少对共享资源的锁定。 要还原一个使用CompletableFuture的不当用法,在异步请求中又嵌入异步调用,导致在依赖服务变慢或请求量变大时产生死锁的场景,可以通过创建两个相互依赖的CompletableFuture任务来实现。下面是一个示例代码: 解释 运行结果 当您运行此程序时,您会发现程序被永久卡住,因为两个CompletableFuture互相等待,导致死锁。 解决方案 避免这种情况的方法是重新设计异步任务的依赖关系,确保不会出现互相等待的情况。可以通过以下方式解决: 例如,使用thenCompose来避免死锁: 在这个解决方案中,future2依赖于future1,并且使用thenRunAsync来避免直接等待,从而避免了死锁。 如何发现这一问题: JStack 是一个分析 Java 应用程序线程状态的有用工具,特别是在诊断死锁问题时非常有用。以下是如何使用 JStack 分析死锁问题的步骤: 步骤 1:获取 Java 进程 ID 首先,需要获取正在运行的 Java 应用程序的进程 ID(PID)。可以使用以下命令找到 PID: 这个命令将列出所有运行的 Java 进程及其 PID。例如: 这里 12345 是 Java 应用程序的 PID。 步骤 2:生成线程转储 使用 jstack 命令生成指定 Java 进程的线程转储: 这将生成一个包含所有线程状态的文件 thread_dump.txt。 步骤 3:分析线程转储 打开生成的 thread_dump.txt 文件,查找死锁信息。通常,如果存在死锁,jstack 输出中会有类似以下的信息:
-
Install Windows 11 ARM on M1-based Macs with UTM
安装详细介绍见官网: https://docs.getutm.app/guides/windows 安装方式一:VHDX 需要事先准备好 1.spice-guest-tools-0.164.4.iso 安装驱动镜像官网下载 2.Windows11_InsiderPreview_Client_ARM64_en-us_26080.VHDX 安装虚拟镜像 下载地址 以下是安装步骤: 安装方式二:ISO 需要事先准备好 1.spice-guest-tools-0.164.4.iso 安装驱动镜像官网下载 2.Windows 11.iso 安装镜像 下载地址 以下是安装步骤: 参考: https://archive.org/download/WIndows-XP-Professional-SP3 https://www.bilibili.com/read/cv22694631 https://wiki.eryajf.net/pages/3f19f0/#_4-%E5%AE%89%E8%A3%85
-
ChatGPT + PlantUML = 不用画图了
PlantUML是一个通用性很强的工具,可以快速、直接地创建各种图表。利用简单直观的语言,用户可以毫不费力地绘制各种类型的图表。支持序列图、用例图、类图、对象图、活动图、组件图、部署图、状态图、时序图。 「毫不费力」这个特点非常有吸引力,当然没那么夸张,还是要费点力气的。它有自己的一套语法,类似于写代码的方式表示各个实体之间的关系、指示要生成哪种类型的图。用过 Markdown 的一下就能理解。 举个例子,下面的代码可以表示 Client 向 Server 发送 Hello。 如果你想自己用它的语法规则,通过写代码的方式画图,可以到官网 https://plantuml.com/zh/ 上学习一下语法。 可以直接在 PlantUML 在线环境上运行 https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000 上方写代码,下面就直接生成对应的 UML 图了,可以调整样式,可以下载各种格式的图片。 也可以在本地安装运行,支持 Java 包运行,也支持 Docker 。 另外,像 VSCode 这些编辑器或者一些笔记软件都有对应的插件支持,可以搜索安装。 ChatGPT + PlantUML 如果你还是觉得不够「毫不费力」,那可以让 ChatGPT 直接生成给你。 打开 ChatGPT ,在「探索 GPT」里面可以搜索 “PlantUML Diagram Wizard”,这个应用是专门用来帮你画 PlantUML 的,但是使用的话需要 GPT-4o,如果超过最大限制,则需要开通 plus 才能用,有实力的同学可以用这个。 不用它也完全可以,我就直接用的免费版 ChatGPT-3.5,效果也没有问题。除此之外,用 Kimi 等大模型应该也问题不大。 那应该怎么给 ChatGPT 提示词呢? 下面我举几个例子,不一定是最好的,但是基本上能解决问题。 用…
-
JSON 可视化工具神器,太好用了!!!
JSON Hero 是一个简单实用的 JSON 工具,通过简洁美观的 UI 及增强的额外功能,使得阅读和理解 JSON 文档变得更容易、直观。 支持多种视图以便查看 JSON:列视图、树视图、JSON 视图等 本地安装 要在本地运行 JSON Hero,首先 clone 源代码,并安装相关依赖项: Then, create a file at the root of the repo called .env and set the SESSION_SECRET value: Then, run npm run build or npm run dev to build. Now, run npm start and open your browser to http://localhost:8787 源码地址 https://github.com/triggerdotdev/jsonhero-web
-
锁竞争激烈的解决方法
在遇到锁竞争激烈的时候,很多开发人员会想到“我需要一个更快的锁”。实际上,某些锁实现机制异常缓慢,对于这类锁,可以使用更快的锁来代替。但是,快慢是相对的,无论锁的速度有多快,都必然会导致线程串行化,因此使用更快的锁对程序性能的提高是一个定值,对程序的可扩展性并无改善。要提高程序的可扩展性,要么不使用锁,要么化解锁的竞争。 在前面讨论死锁时,曾经提到可以通过复制资源的方式来避免使用锁。只要可行,这是一个非常好的解决方法。这样,每个线程访问自己的资源副本,从而可以避免使用锁。如果有需要的话,可以在程序的最后将各个线程占有的资源副本合并成一个单一的共享资源副本。 根据排队理论,一个资源闲置得越少,要得到它的平均等待时间就越长。这种关系是非线性的;如果锁的个数翻倍,平均等待这个锁的时间就比原来的两倍还要多。减少对锁的等待时间的最有效方法是减少这个锁所保护的范围大小。所以如果某个资源无法被复制,就可以考虑将该资源分割成若干个部分,然后用彼此独立的锁分别保护分割以后的各个部分。考虑多个线程同时向一个散列表中插入数据的情形。为了避免数据竞争,每个线程在访问散列表的时候都需要对散列表加锁。这种方案存在一个重大的缺陷,所有的线程都必须竞争同一个锁,这就形成了一个性能瓶颈。于是我们可以通过一个散列函数,将关键字映射到一个子表,并且使每个子表有一个独立的锁。对于一个给定的关键字,线程可以使用散列函数将关键字映射到一个子表,然后线程取得这个子表的锁,再对这个子表进行操作。只要有足够数量的子表和足够好的散列函数,线程之间就不会出现竞争同一个子表的锁的情况。 基于将竞争分担到多个锁的思想,出现了细粒度锁(fine-grained locking)的概念。例如,散列表一般是以桶数组(array of buckets)的方式实现,数组中每个桶都包含被映射到同一数组元素的关键字。在细粒度锁机制中,每个桶上都可能有一个锁。这样,多个线程就可以并发访问不同的桶。如果桶的数量固定,就可以直接实现。但是如果桶的数量必须不断增加,情况就比较复杂,因为进行数组大小变化时,锁将锁定整个桶数组,这就意味着只有进行当前操作的线程能够访问桶数组,其他的线程都被拒绝访问。可以使用读写锁解决这个问题。这种机制的另一个缺点是如果桶容量很小,那么锁的空间开销就会变得很显著。 如果一个数据结构读取频繁但是写入并不频繁,就可以使用读写锁(reader-writer lock)来解决竞争。读写锁可以区分写入者和读取者。多个读取者可以同时获取锁,但某一个时刻只有一个写入者可以获取锁。读取者在写入者持有锁的时候不能获取锁。 在多数访问为读访问,而写访问频率较低、持续时间也比较短的情况下,读写锁的性能最好。多个读线程与单个写线程交替进行操作,所以读线程和写线程都不会长时间阻止。 一个线程可以持有读线程锁或写线程锁,但是不能同时持有两者。 读线程和写线程将分别排入各自的队列。当线程释放写线程锁时,此刻读线程队列中的所有等待线程都将被授予读线程锁;当已释放所有读线程锁时,写线程队列中处于等待状态的下一个线程(如果存在)将被授予写线程锁,依此类推。换句话说,ReaderWriterLock 在一组读线程和一个写线程之间交替进行操作。 当写线程队列中有一个线程在等待活动读线程锁被释放时,请求新的读线程锁的线程会排入读线程队列。即使它们能和现有的读线程锁持有者共享并发访问,也不会给它们的请求授予权限;这有助于防止写入者被读取者无限期阻塞。 大多数在读写锁上获取锁的方法都采用超时值。使用超时可以避免应用程序中出现死锁。例如,某个线程可能获取了一个资源上的写线程锁,然后请求第二个资源上的读线程锁;同时,另一个线程获取了第二个资源上的写线程锁,并请求第一个资源上的读线程锁。如果不使用超时,这两个线程将出现死锁。如果超时间隔过期并且没有授予锁请求,则此方法通过引发ApplicationException 将控制返回给调用线程。线程可以捕捉此异常并确定下一步要进行的操作。 在使用细粒度锁的时候,需要提到的一点是过细粒度将增加对锁的请求和释放的频率,因而会增加额外的指令。您必须在过细和过粗粒度之间找到平衡。最佳粒度不得不通过试验找到。下图显示了锁的吞吐量和粒度之间的关系。 图:锁的吞吐量和粒度之间的关系 这个图是一个简单的双坐标轴图表。垂直轴或 y 轴表示吞吐量。水平轴或 x 轴表示粒度,沿着坐标标尺向外移动时粒度从精细到粗糙而变化。一条延长的贝尔曲线表明了粒度对吞吐量的关系。随着粒度从精细到粗糙,吞吐量逐渐增加到一个最大水平,然后开始慢慢下降。这表明为了达到最大吞吐量,必须在粒度上折衷。
-
业务开发处理流程:注意和考虑LIST
序号 分类 内容 备注 1 业务评审 需求背景,期望目标 业务是否合理 2 业务流程、交互方式 3 技术评审 整体架构设计(架构图) 技术是否合理 4 数据模型设计 5 关键技术、核心算法 6 数据交互方式 7 核心接口设计 8 中间件 消息中间件 配置是否申请 9 任务调度 10 搜索引擎 11 文件存储 12 数据安全 历史数据处理 13 数据补偿方案 14 灰度方案 客户端灰度 15 接口灰度 16 回滚策略 17 系统性能 需求系统性能 TPS、RT、VU(并发用户数)各是多少? 18 随着数据量的增大系统性能会不会出现明显问题 19 系统哪个环节会是最大的瓶颈?系统性能拐点是那里? 20 是否打算做压力测试?做哪些类型的压力测试,为何?压力测试方案是怎么样的? 21…
-
MybatisPlus中like查询匹配多个字段用法
写法如下: 控制台打印sql语句如下:
Got any book recommendations?