IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:并发

共 32 篇相关文章

IT 累计浏览 3,707

【死磕Java并发】—–Java内存模型之happend-before

这篇深入探讨了Java并发编程中一个关键却容易混淆的概念:happens-before原则。作者从多线程环境下变量修改的可见性问题出发,解释了JMM如何通过happens-before来建立内存可见性的保证。 文章系统梳理了happens-before的八大核心规则,例如程序次序规则(单线程内操作有序)、volatile变量规则(写操作对后续读操作可见)以及锁定规则(解锁先于加锁)。除了这些JVM原生规则,作者还列举了诸如线程安全集合操作、Future.get()等场景下的六条推导规则,构建了完整的判断体系。 为了帮助理解,文章通过简单的代码示例,一步步演示了如何应用这些规则来判断一段非同步代码是否存在线程安全风险。它明确了happens-before的本质:它并非强制操作顺序,而是保障了在存在该关系时,一个操作的结果对另一个操作的可见性。这为我们在并发编程中分析数据竞争、设计线程安全代码提供了根本依据。

IT 累计浏览 3,380

[Java基础教程]第十三章-Java多线程

这篇讲的是Java多线程,作者从“如何让服务器同时处理多个客户端”这个实际问题出发,解释了并发编程的必要性。文章用一个生动的买票比喻,把“串行”、“并行”和“并发”这三个容易混淆的概念讲得明明白白:排队是串行,多窗口同时卖票是并行,而一个售票员同时应付多个询问者则是并发。 更深入一点,作者还探讨了为什么在多核CPU普及的今天,讨论并发时常常仍基于单核模型,点明了任务调度、内存访问等现实约束。核心部分是用Java的Thread类重构服务器代码,展示了如何为每个新连接创建独立线程来处理。文章不仅给出了基础实现,还进一步模拟了10个用户同时连接的场景,并加入了一个将聊天记录缓存后批量写入文件的ChatLogManager类,让示例更贴近生产环境中的考量。 整体而言,这篇教程从概念辨析到代码实践,一步步带着读者理解并发的本质,并快速掌握Java多线程编程的入门要点。

IT 累计浏览 3,439

操作系统-进程管理

这篇系统梳理了操作系统进程管理的核心概念。作者从最基础的定义切入,指出进程是程序的一次动态执行过程,并详细对比了它与静态程序在存在形式、生命周期、资源分配角色上的五大关键差异。 文章接着拆解了进程的内部构成,重点呈现了进程状态的演进——从经典的三种状态模型,到更贴近实际的五种、七种状态切换图,这直观反映了现代操作系统对进程调度的精细化控制。在调度层面,文章清晰列举了先到先服务、优先级、最短作业优先、循环轮转以及多级队列这五种经典算法,为理解CPU资源如何公平高效地分配给不同进程提供了具体思路。 此外,文章也涵盖了进程间通信的七种主要方式(如管道、共享内存、套接字等),并最终引向了更轻量的执行单元——线程,明确了进程与线程在资源分配与调度层面的分工关系。整篇内容结构清晰,从定义到组件,再到调度与通信,最后延伸到线程,为构建操作系统进程管理的完整知识图谱提供了扎实的路线。

IT 累计浏览 998

在 Perl6 脚本中并发执行 ssh 命令

这篇讲的是作者在 Perl6 中并发执行 SSH 命令时的一次实战尝试。由于找不到合适的现有模块,且底层 C 库不兼容其 Kerberos 认证环境,作者决定绕开高层并发 API(如 Promise/Supply),直接使用更底层的 Thread 和 Channel 来实现。 文章围绕一个简洁的 OpenSSH 类展开,展示了如何通过多方法实现单个主机与多主机的命令执行。作者特别指出,虽然 Perl6 宣传了高级并发模型,但 API 迭代较快,有时选择更稳定的底层原语反而更可靠。 代码示例串联了不少 Perl6 语法点:类的属性定义、字符串连接符 `~`、用于捕获错误的 `try`/`CATCH`、执行系统命令的 `qqx{}`,以及 `>>` 操作符在数组上的线程化 finish 操作。作者也坦诚,示例代码较为简陋,例如依赖密钥登录且未使用线程池调度。 整体来看,这是一份结合了具体需求、实现思路与语法讲解的笔记,既分享了在 Perl6 中集成系统命令与并发控制的方法,也客观分析了语言特性在实际场景下的应用考量。

IT 累计浏览 3,678

JAVA多线程面试题

这篇文章系统梳理了Java多线程领域最常被问及的25个核心问题,堪称一份精炼的面试准备与知识巩固指南。 内容覆盖了从基础概念到底层原理的完整链条。开篇便厘清了进程与线程的根本区别,指出线程作为“轻量级进程”如何共享资源以提升效率。随后深入剖析了线程的创建方式(实现Runnable接口与继承Thread类)、生命周期状态(从New到Dead的流转),以及用户线程与守护线程的关键差异。 文章不仅止于理论,更聚焦于实战与调优。它详细解释了线程间通信的底层机制——为什么wait()、notify()等方法定义在Object类中且必须在同步块内调用,并对比了同步方法与同步块的性能影响。对于并发编程中的痛点,如线程安全,文章列举了同步、volatile、原子类等多种保障手段。关于死锁的分析、线程池的创建、以及ThreadLocal的用途,也都给出了清晰的定义与实用的指导。最后,文章还涉及了线程转储(Thread Dump)的获取与分析,为解决复杂并发问题提供了工具。 整体而言,这篇文章没有泛泛而谈,而是将每一个“为什么”和“怎么做”都讲得扎实具体,非常适合Java开发者用来查漏补缺,快速构建起关于多线程面试与实践的知识框架。

IT 累计浏览 2,019

Erlang公平调度的误解

这篇讲的是Erlang引以为傲的“公平调度”哲学,在实际工程中可能并不像想象中那么完美。作者从Erlang虚拟机(BEAM)的时间片分配、抢占式调度说起,点明了它在云计算等场景下保障用户体验的初衷。 但文章的重点在于“祛魅”。作者指出,尽管Erlang的BIF、NIF等模块都在努力维护公平,但一些基础设计环节却可能无意中打破这种平衡。例如,消息队列的无保护单向队列结构,在极端负载下可能导致队列暴增和内存激增;而内存分配器在向系统申请内存时使用的锁,以及SMP架构下难以避免的锁竞争,都可能成为公平性的破坏者。文章最终总结,这些实现细节上的“坑”影响了Erlang在某些情况下的公平性表现,也解释了为何近期Erlang引入dirty scheduler等新机制来应对。 作者最后将视角拉高,提醒架构师需从上到下,在业务层面也进行“公平”设计,才能与系统哲学和谐统一。世界没有绝对公平,但理解其边界至关重要。

IT 累计浏览 2,559

Go 语言简介(下)— 特性

这篇讲的是Go语言的核心并发特性。作者从通勤时间的利用切入,用一系列简洁的代码示例,带你快速上手Go中并发编程的四大金刚:goroutine、原子操作、Channel以及它们的安全性问题。 文章首先展示了如何用`go`关键字轻松启动goroutine,就像给函数调用加了“并发”开关。但真正的并发需要配置`runtime.GOMAXPROCS`。作者特意用一个经典的“卖票程序”作为例子,直观地演示了当多个goroutine同时修改全局变量时,若无保护,票数竟会变成负数。随后,他引出了解决并发数据竞争的两种核心武器:使用`sync.Mutex`互斥锁进行显式加锁,以及对于简单计数器使用`sync/atomic`包进行无锁的原子操作,后者通过一个期望结果为200的累加实验说明了其效率与正确性。 最后,文章聚焦于Go的通信哲学核心——Channel。通过示例代码,清晰地讲解了Channel如何充当goroutine间安全的通信管道,包括如何设置缓冲区大小,以及利用其默认的阻塞特性来协调收发双方的节奏,避免了直接共享内存带来的复杂锁问题。整篇文章用最简短的上下班时间,帮你建立起对Go并发模型从基础到实践的关键认知。

IT 累计浏览 4,477

Jetty线程“互锁”导致数据传输性能降低问题分析

这篇讲的是在Jetty 7.2.1这个特定版本中,一个会导致数据传输性能降低的“互锁”问题。作者从Jetty经典的NIO异步反映器模型入手,分析了主线程(selector)与子线程(工作线程)之间的一种微妙配合失误。 问题的核心在于,当子线程遭遇网络拥塞、缓冲区写满时,它会进入阻塞状态并向主线程注册一个内部事件,等待拥塞解除的通知。然而,主线程的select循环在等待selector的网络事件时,可能并未及时轮询和处理这些内部事件,导致子线程无法被唤醒,形成“互锁”,拖累了整体性能。 文章通过拆解具体的代码逻辑,清晰地展示了这种线程间交互的瓶颈点。最终,作者指出了相应的解决或规避思路,比如合理设置超时参数,以帮助开发者在类似场景下优化配置,避免性能陷阱。

IT 累计浏览 1,704

erlang和其他语言读文件性能大比拼

这篇讲的是不同语言在处理大文件读取时的性能较量,主角是Erlang。作者从公司一次技术比武的真实案例出发——有同事用Erlang处理1.1GB文本的词频统计耗时55秒,而用C只需2.6秒,Java为3.2秒——引出了一个普遍疑问:Erlang读文件真的这么慢吗? 为了重新验证,作者准备了一个1GB的测试文件,详细对比了多种读取策略的性能。数据很有说服力:在单线程缓冲读取模式下,Erlang耗时0.322秒,与C语言的dd命令(0.264秒)处于同一量级;而启用多线程并发读取后,耗时缩短至0.214秒,性能甚至超越了C语言。但反例也很明显,如果以4KB小块读取,耗时会骤增至3.56秒,性能急剧下降。 文章揭示了性能差异背后的核心机制:Erlang的文件IO通过efile驱动实现,本质是轻量级的C封装,但每次操作都涉及“发消息→驱动执行→等待结果”三个阶段。这种设计在IO操作粒度过小时,消息传递开销会被放大,违背了Erlang“小消息,大计算”的原则。因此,性能的关键在于使用大块缓冲区读取,并充分利用异步线程池并行化IO,从而将Erlang的IO性能推到理论极限。

IT 累计浏览 3,265

不同SSD盘组合搜索引擎单机性能测试[2013年版]

作者从搜索引擎单机性能优化的需求出发,在一台配置了24核Xeon E5 CPU、近50GB内存的Linux服务器上,对不同SSD盘组合策略下的HA3引擎性能进行了系统测试。测试数据规模可观,索引达59G,摘要73G。 文章详细对比了多种方案:从全内存基准、单盘SSD,到由两块或三块盘组成的RAID 0、RAID 1,以及不使用硬件RAID而采用软连接或数据分片的方式。测试严格控制了IO调度、预读、线程数等变量,并通过abench工具获取峰值QPS。 核心发现颇具实用价值:当索引量翻倍时,性能近似减半,表明IO是关键瓶颈。单纯增加RAID 0的磁盘数对搜索引擎引擎性能提升有限,瓶颈会转移至CPU锁开销。最引人注目的结论是,两块SSD盘不使用硬件RAID,而是通过软件将数据按term哈希键分片存储,能达到约18%的性能提升,优于RAID 0的12%提升,也远超传统的多段软连接方式。 文章最终给出了分层建议:在CPU性能制约时,应重点解决IO瓶颈(如采用多盘按term切分);当磁盘增多后,则需关注CPU锁优化。对于写入场景,也提出了普通盘与SSD搭配的实践方案。

IT 累计浏览 2,413

Ruby的多线程应用服务器介绍

这篇讲的是随着Rails 4.0默认开启多线程模式,Ruby Web开发迎来了多线程服务器选型的新阶段。作者对三款主流选择进行了对比分析。 Rainbows和Puma都支持master-worker集群模式,能充分利用多核服务器。Rainbows脱胎于稳定的unicorn,提供了丰富的进程控制信号,适合对稳定性和运维控制要求高的大型应用。Puma的特色在于线程数可根据请求量在设定范围内自动伸缩,且单进程模式更节省内存,对中小型应用更友好。而Zbatery是极简的单进程多线程版本,是三者中最省内存的,适合在VPS上托管多个低流量应用。 作者的性能测试显示两者差异不大,选择更多取决于场景:追求稳定与可管理性选Rainbows,希望节省资源与灵活伸缩则Puma更佳。

IT 累计浏览 5,835

whatsapp深度使用Erlang有感

当很多人还在争论Erlang是否过于小众、能否胜任大规模商业系统时,WhatsApp用事实给出了响亮的回答。这篇文章分享了作者对WhatsApp深度使用Erlang技术栈的观察与思考。 文章的核心是一个极具说服力的案例:一个以Erlang为主的后台架构,支撑了数亿用户。作者通过引用WhatsApp主要开发者Rick Reed的分享,揭示了一个有趣的成长故事——这位有深厚系统性能背景的工程师,在2011年加入WhatsApp时竟是一位Erlang新手,但短短两三年后,他已能将Erlang的虚拟机、集群、Mnesia数据库等特性运用到极致。 文中列举的数据令人印象深刻:仅用两台服务器承载百万级的长连接、Mnesia数据库支撑起巨大的数据集,以及背后惊人的消息吞吐量。作者指出,Rick Reed的工作并非创造了全新的魔法,而是将Erlang已知的特性进行了系统化整理并坚决落地于商业系统,这是从理论到实践的巨大飞跃。 文章最终的结论很直接:任何系统开发到最后,都是在操作系统和硬件能力的边界内解决同类问题,Erlang为解决高并发、高可用等特定规模问题提供了坚实的基础。作者鼓励读者停止对它的怀疑,因为它在正确的场景下确实能带来巨大的价值。

IT 累计浏览 5,425

Servlet线程安全问题

这篇讲的是开发中容易踩到的陷阱:Servlet的线程安全问题。文章从Servlet默认的多线程执行模型切入,指出当多个线程并发访问同一个Servlet实例时,如果代码不当,会产生难以复现的bug。 作者用了一个很直观的代码案例:在service方法中使用了一个实例变量PrintWriter。当用户a和b几乎同时请求时,由于线程调度和共享实例变量,用户a的浏览器收到了空白页,而a的信息却错误地显示在了用户b的页面上。文章进而从Java内存模型(JMM)的角度,分析了线程工作内存与主内存的同步延迟,如何导致了这一问题的随机性与危险性。 针对该问题,文章总结了三种解决方案:一是实现SingleThreadModel接口(但已被废弃,且不能解决所有问题);二是使用synchronized关键字同步代码块;最根本的,是避免在Servlet中使用实例变量,将需要的数据作为局部变量处理。这对于理解Web容器如何执行Servlet,以及如何编写可靠的并发代码,都是很好的一课。

IT 累计浏览 3,740

用pigz代替gzip

这篇讲的是一个名为pigz的并行压缩工具,作者通过实际测试,展示了它相比传统gzip在现代多核处理器上的巨大性能优势。 pigz的核心是利用多线程并发执行gzip算法。文章用两组大文件(约2.3GB和5.2GB)的压缩解压测试数据做了直观对比。结果显示,pigz在默认线程数下,压缩速度可达gzip的5.3倍。例如,压缩那个5.2GB的文件,pigz默认配置耗时1分12秒,而gzip则需要超过6分钟。解压缩同样快了一倍以上。虽然pigz会消耗更多CPU资源,但压缩比与gzip相当。 文章还深入分析了线程数与性能的关系。实测表明,从4线程增加到8线程能带来约41%的速度提升,但从8线程增加到16线程提升降至28%左右,而32线程对比16线程仅提升3%,存在明显的边际效益递减。 因此,结论很明确:在需要快速压缩大文件、且能接受短时间高CPU负载的场景下,pigz是一个能极大提升工作效率的替代方案。

IT 累计浏览 4,592

为什么我们要使用Go语言以及如何使用它的

这篇讲的是SoundCloud团队为何在多种编程语言并行的后端架构中,选择引入Go语言,以及他们基于1.0版本Go的具体实践经验。 作者从公司已有的技术栈(最外层是Ruby on Rails)出发,坦诚了后端语言混杂的现状。核心观点是,Go语言为解决特定场景下的问题——比如性能敏感、需要高并发处理的服务——提供了一个清晰而有力的选项。文章没有停留在语言特性的泛泛对比,而是结合SoundCloud自身的业务需求,分享了Go在实际项目中的应用思路,包括如何集成到现有系统、其编译型语言带来的部署便利性,以及在处理并发任务时的天然优势。 对于同样面临多语言架构管理复杂度、或寻找特定后端模块优化方案的技术团队而言,这篇结合了一线公司选型思考与实践的分享,提供了相当具体的参考。

IT 累计浏览 11,489

Rolling cURL: PHP并发最佳实践

这篇讲的是在PHP中如何通过cURL的curl_multi_*族函数实现高效并发请求。作者从实际场景出发,比如新闻聚合、商品价格监控或比价工具,这些任务往往需要批量抓取多个URL的数据。传统逐个请求的方式效率很低,而curl_multi_*提供了一个轻量级的并发解决方案。 文章具体拆解了实现并发请求的核心步骤:如何初始化多个cURL句柄、将其加入批处理、执行并发传输,以及最后高效地收集和处理各个请求的结果。它强调了这种方法在IO密集型任务中的显著性能提升,相比串行执行能大幅缩短总耗时。 作者通过实际案例,展示了这套方案在中小型项目中的适用性。它不需要引入复杂的异步框架,就能有效解决常见的批量数据获取瓶颈,为开发者提供了一个实用且易于落地的优化思路。

IT 累计浏览 8,100

C++ 多线程编程总结

这篇讲的是C++开发者在追求高并发与实时性时,如何通过多线程编程提升程序效率的实战心得。作者从实际开发需求出发,没有空谈理论,而是直接总结了几类常见的多线程优化路径。 文章内容扎实,比如会具体聊到如何创建和管理线程以避免不必要的开销,对比不同同步原语(如互斥锁、条件变量)的适用场景与性能权衡,以及如何设计任务队列来平衡负载。这些经验点直指开发者日常编码中的真实痛点。 对于正在处理高并发服务、实时计算或对延迟敏感的系统性能瓶颈的工程师而言,这种将散落在各处的实践知识系统化的梳理很有价值。它能帮助你在方案设计阶段就考虑到关键的多线程因素,避免后续踩坑。

IT 累计浏览 1,884

HandlerSocket返回错误码167的bug分析

这篇讲的是一个实际生产中遇到的性能陷阱:当使用HandlerSocket向多个采用自增主键的InnoDB表进行高并发写入时,会频繁触发错误码167,导致事务处理性能断崖式下跌。 作者从问题现象入手,追踪了167错误码背后的内核机制。分析指出,问题的核心在于HandlerSocket的写入操作与InnoDB自增锁(AUTO-INC Lock)的交互方式。在高并发下,多个写入线程为了获取下一个自增值而产生严重锁竞争,进而引发队列堆积和错误返回,最终拖垮整体TPS。 文章进一步探讨了优化思路,可能涉及调整InnoDB的自增锁模式、或重新评估在高并发写入场景下使用HandlerSocket的适用性,为遇到类似问题的开发者提供了直接的排查方向和优化参考。

IT 累计浏览 5,339

Nginx 还是 Varnish?

这篇讲的是,在Web架构中,选择Nginx还是Varnish做HTTP加速和缓存层,这个经典的“甜蜜烦恼”。作者从实际部署场景出发,拆解了这两款顶级工具的核心差异。 核心对比在于它们的角色定位:Nginx更像一个全能型的反向代理和负载均衡器,同时兼具出色的静态文件服务和基本的缓存能力,适合作为架构的“入口门卫”。而Varnish则是一个“偏科生”,它牺牲了部分通用性,专注于将HTTP加速和缓存做到极致,其VCL(Varnish Configuration Language)提供了对缓存策略像素级的灵活控制。 两者的关键差异直接决定了它们的适用场景。如果需要一个稳定的流量网关,并希望用单一组件解决静态服务、代理和简单缓存等问题,Nginx是更直接、更一体化的选择。而如果业务场景对页面缓存性能有极高要求,流量模式复杂,需要编写极其精细的缓存规则(例如根据URL、Cookie或设备类型做差异化缓存),那么Varnish的专用性和性能优势会更明显。 文章也暗示了两者并非互斥,在许多生产环境中,它们常被组合使用:让Varnish作为前端缓存猛将,Nginx在后面处理静态资源和动态请求的代理分流。这种搭配既发挥了Varnish的缓存性能,又利用了Nginx的生态和多功能性。最终选型,还是要回到你具体的业务流量、缓存策略复杂度以及运维团队的技术栈偏好上来判断。

IT 累计浏览 2,011

Erlang进程简单的主动负载管制实现

这篇讲的是如何解决Erlang虚拟机中一个常见但容易被忽视的性能问题:调度器的时间片机制虽然保证了公平性,但对IO密集型进程并不友好。当进程进行大量IO操作时,其消耗的“时间片”实际上并不准确,这会导致CPU计算密集型进程在对比中吃亏。 文章作者从这个实际痛点出发,设计并实现了一种简单的主动负载管制机制。核心思路是让进程在执行耗时操作前,主动“让出”部分时间片,而不是被动等待调度器强制切换。这样,系统就能更公平地分配CPU资源,避免因IO操作而导致的不公平现象。 实现上,文章展示了如何利用Erlang的内置工具进行轻量级监控,并在进程内部嵌入负载检查与自我调节的逻辑。这种方案不需要复杂的外部框架,保持了Erlang轻量级进程原有的优势。