synchronized不适合高并发限流计数器,因其严重串行化导致吞吐量骤降、线程频繁阻塞;仅适用于单机低QPS、调试或教学等轻量场景,需明确其逻辑正确但性能受限的边界。

纯 synchronized 在高并发下不适合构建高性能限流计数器,因为它会严重串行化访问,导致吞吐量骤降、线程频繁阻塞。但若场景极轻量(如单机低QPS、调试用途、或作为教学示例),可基于它实现一个**逻辑正确但性能受限**的简单计数器。关键在于明确它的适用边界和结构要点。
核心设计:synchronized 保护共享状态
限流本质是控制单位时间内的请求数。最简模型需两个要素:计数器值 + 时间窗口判断。用 synchronized 方法或代码块包裹所有读写操作,确保原子性:
- 每次请求进来,先检查是否在当前时间窗口内;不在则重置计数器和窗口起始时间
- 在窗口内且计数未超阈值,则计数+1并放行
- 否则拒绝请求
基础实现示例(固定窗口)
以下是一个线程安全但非高并发友好的实现:
public class SimpleRateLimiter {
private long count = 0;
private long windowStart = System.currentTimeMillis();
private final long windowMs; // 窗口毫秒数,如 1000 表示 1 秒
private final long limit; // 每窗口最大请求数
<pre class="brush:php;toolbar:false;">public SimpleRateLimiter(long windowMs, long limit) {
this.windowMs = windowMs;
this.limit = limit;
}
public synchronized boolean tryAcquire() {
long now = System.currentTimeMillis();
// 窗口已过期,重置
if (now - windowStart >= windowMs) {
count = 0;
windowStart = now;
}
// 尝试通过
if (count <p>}</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7377" title="Java Maven Secondary Analysis"><img
src="https://img.php.cn/upload/skill/000/000/081/179144831942131.jpg" alt="Java Maven Secondary Analysis" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7377" title="Java Maven Secondary Analysis" class="overflowclass">Java Maven Secondary Analysis</a>
<p class="overflowclass">分析ZIP压缩包或GitLab仓库中的Java Maven项目,确定二次开发范围、类数量、模块分布及生产相关指标。</p>
</div>
<a rel="nofollow" href="/xiazai/skill7377" title="Java Maven Secondary Analysis" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>为什么它“不能用于高并发”
问题不在逻辑错误,而在执行瓶颈:
- 所有线程竞争同一把锁(实例锁),哪怕只是读取
count和windowStart也必须排队 - CPU 缓存行伪共享不构成主要问题,但锁争用会导致大量线程进入
MONITORENTER阻塞态 - 实测在 100+ 线程并发时,吞吐量可能不足 1 万 QPS,远低于现代应用需求
若坚持用 synchronized,可做的微优化
无法消除锁瓶颈,但可减少临界区耗时、避免误判:
- 只在真正需要更新状态时才进入同步块:先快速读取(非原子,但可接受短暂脏读),再按需加锁校验
- 使用
System.nanoTime()替代currentTimeMillis(),精度更高、开销略低 - 避免在同步块中调用外部方法(如日志、网络),防止锁持有时间不可控
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










