第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

顛覆認(rèn)知!synchronized 的輕量級(jí)鎖竟然還會(huì)自旋?

標(biāo)簽:
Java JavaScript

原文来自于:https://zha-ge.cn/java/99

颠覆认知!synchronized 的轻量级锁竟然还会自旋?

前些天,项目组里刮起一阵“性能优化”旋风。大家嘴里念叨得最多的,就是 synchronized。你以为 synchronized 还停留在“重量级锁开销大、能不用别用”的时代?哎,too young, too simple。有同事突然冒出一句:“你知道轻量级锁会自旋么?” 我心里那个一惊,啥玩意?自旋我知道,但不是只有自旋锁(spin lock)和偏向锁那一套撩妹操作么?轻量级锁还能自旋?我的认知小船翻了。


说起来,本来我一直用了十几年的 synchronized,早就当它透明胶带:粘一粘,线程安全就稳了。直到看热心网友贴出来的 JVM 官方文档,才发现原来 synchronized 内部也有个熬夜加班的“小老弟”——自旋。

synchronized 锁升级流程:

  • 偏向锁
  • 轻量级锁(可能自旋)
  • 重量级锁(OS 层阻塞)

你没看错,真·自旋,出现在了轻量级锁阶段!


探索过程:锁的“瘦身房”与自旋岗

那天熬夜调代码,忍不住扒拉出 jvisualvm 跟踪锁的情况。说实话,一开始我还以为自旋只跟 ReentrantLock 那种高阶锁精英挂钩,synchronized 这种老实人不会玩这一套。谁知道 JVM 1.6 以后,synchronized 静悄悄地玩起了锁升级+自旋优化!

简单来说,轻量级锁抢不到怎么办?慌什么!线程先自旋个几次——有机会就抢过来,没机会再罢休。换句话说,JVM 在“阻塞”之前还会帮你“抢红包”兜底几下,说不定你卡个 1ms 就能等到 CPU 空。

我随手写了个脑筋急转弯式的多线程代码测试([完整示例略]),线程争锁的时候明显能感觉比老版 JVM 更“丝滑”。

只看关键代码逻辑:

synchronized (lock) {
    // 临界区代码
    doSthImportant();
}
// JVM 内部:如果锁已轻量级化,CAS 尝试获取锁
// 若失败,线程本地自旋次数,等锁释放再抢

你看,JVM 真不是简单粗暴地让你傻等。


踩坑瞬间

当然,自旋背后也有坑货时刻。举个例子:

  • 多线程并发极高时,轻量级锁依然会撑不住,很快升级成“重量级锁”,从会场 VIP 区秒变大排长队,性能立马暴跌。
  • 自旋也是“徒劳等待”——万一锁持有者忙着GC或I/O,兄弟你再怎么转也只是在原地打转,CPU 就这么白白烧光。

我有次手贱把 synchronized 放到了很大的代码块上,结果 CPU 飙升,线程堆积,“自旋”变成了“原地画圆”(线程:我到底在等什么?)。真是又气又好笑。


经验启示

码代码久了,归纳如下几点生存小妙招:

  • synchronized 其实很聪明,JVM 已帮你做了不少“骚操作”,不用过分妖魔化它。
  • 遇到频繁竞争,锁粒度要细,临界区能短则短,别让自旋线程干等太久。
  • 想极致性能且偏好 DIY,可以考虑显式用 java.util.concurrent 包里的锁,但别轻视 synchronized 的进化史。
  • 工具很重要,有事多用 jstack、jvisualvm 等实时监控,别拍脑袋猜测锁状态。

最后,synchronized’s not dead。别小瞧了轻量级锁下那颗自旋的心。从此,每次写 synchronized,总感觉背后有个 JVM 小哥在我耳边说:“兄dei,放心,让我帮你兜一把!”


好啦,今天先聊到这,码字都快饿了。谁能想到 synchronized 背后藏了那么多脑洞呢?下回也许还得扒拉扒拉偏向锁的故事……下期再见👋。

从提交到执行:一只小任务在 Java 线程池的奇幻漂流

有时候我觉得,写业务的自己像个无情的“丢任务机器”——啪一个threadPool.submit(task),丢进池子,然后就不管了。可你真的知道,这支“任务小船”在池子里都经历了什么浪花拍打才驶到岸边的吗?来吧,今天聊点八卦,揭秘一下线程池底下那些“不为人知的故事”。


一波操作猛如虎

记得那天领导说:“你这接口别堵了,整块线程池异步处理!”名正言顺开撸。代码很行云流水:

ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> doWork());

就这两行,写得我还以为快成并发大师了。其实submit()真不是你想的那样傻瓜——背后的门道,还真有点意思。

  • 先来看,线程池接住任务后,小船先停泊在哪?
    • 工作队列(workQueue)。
  • 线程池本身,有几种“水流”状态(RUNNING、SHUTDOWN那些)。
  • 真正“起锚”的,是哪段代码?又是怎么分配帆手(线程)的?

一定得追,毕竟咱每加一个线程,都是在“烧钱”(内存,切换开销什么的),池子大,责任也大。


踩坑瞬间

可小船不是每次都顺利靠岸。

有回想着提速,把corePoolSize拉到8,最大maximumPoolSize拉到16,队列换成了ArrayBlockingQueue,任务一丢……咦,居然爆得比老坛酸菜还快!

而且让人更崩溃的是——有时候任务死活不执行,线程池活像摆烂。“这什么情况?”翻源码,一步步debug下去,才发现大坑:

  • 队列满了,线程池满了,拒绝策略发挥作用。
  • 肯定是“提交大于并发上限+队列可容纳”,剩下的全被RejectedExecutionHandler无情抛弃。

关键一幕代码其实就是它:

if (workerCount < corePoolSize) {
    addWorker(command, true);
} else if (workQueue.offer(command)) {
    // 入队等待
} else if (workerCount < maximumPoolSize) {
    addWorker(command, false);
} else {
    reject(command);
}

就是这顺序,决定了你的“船票”能不能买进。队列满了,浪费得不亦乐乎。


那到底,任务的奇幻漂流是啥流程?

总结下,大致就这样:

  1. 判断现在有几个“划船工”(活线程)。
  2. 没达到corePoolSize,直接搞线程执行;
  3. 达到了,任务塞队列,等空位;
  4. 队列也塞不动了,看能不能扩到maxPoolSize拉新线程;
  5. 全满,打回票,RejectedExecutionException,你猜谁背锅?

你可以想成夜间酒吧排队,座位(线程)满了,就只能在门口排队等(队列),等不下了只能通知门外已经打烊(拒绝策略)。


经验启示

  • 线程池不是黑箱,有些默认策略坑多得很。
  • 打印自定义日志监控线程池参数,千万别“装作没事发生”。
  • 队列满与否要精心设计,高并发下LinkedBlockingQueueArrayBlockingQueue可不是一个味道。
  • 拒绝策略用CallerRunsPolicy,业务方别全指望池子兜底。
  • corePoolSize、maxPoolSize 和 队列容量,一定要结合业务压力多测几轮别脑补。

写着写着感觉自己像讲完了一部《线程池漂流记》。码农世界就是这样,海浪和暗礁比海岸还多,偶尔会被拍醒,但醒着思考也挺酷的。好了,今天故事讲完,咖啡续上,代码再优化一把,下次希望任务小船全都平安靠岸吧!

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消