type
status
date
slug
summary
tags
category
icon
password
Property
Jan 16, 2025 07:59 AM
在复习一些关于
java.util.concurrent
的知识点的时候,我突然悟出了一些道理,仅供分享。起因:
在粗略看ConcurrentHashMap的源码的时候,我发现了一个注释:
lost initialization race; just spin
这种技术思想在实现单例模式的时候也有体现:
在这个模式中:
- 第一次检查(
if (instance == null)
)是为了避免不必要的同步。
- 第二次检查(
if (instance == null)
)是为了确保只有一个线程能够初始化实例。
volatile
关键字用于防止指令重排序,确保其他线程能够看到完全初始化的实例。
“Lost initialization race” 的含义
在多线程环境下,可能会出现以下情况:
- 线程 A 进入
getInstance()
方法,发现instance
为null
,于是进入同步块。
- 线程 A 开始初始化
instance
,但在初始化完成之前,线程 B 也进入getInstance()
方法。
- 线程 B 发现
instance
仍然为null
(因为线程 A 还没有完成初始化),于是也尝试进入同步块。
- 由于同步块的互斥性,线程 B 会被阻塞,直到线程 A 完成初始化并释放锁。
在这种情况下,线程 B “丢失了初始化竞争”(lost initialization race),因为它没有抢到初始化的机会。
“Just spin” 的含义
“Just spin” 的意思是,线程 B 在发现
instance
为 null
后,可以选择 自旋等待(spin-wait),而不是立即进入阻塞状态。自旋等待是指线程在一个循环中不断检查条件(例如 instance != null
),直到条件满足为止。自旋等待的优点是:
- 避免了线程上下文切换的开销。
- 在初始化操作很快完成的情况下,自旋等待可能比阻塞更高效。
自旋等待的缺点是:
- 如果初始化操作耗时较长,自旋等待会浪费 CPU 资源。
- 在高并发场景下,大量线程自旋等待可能会导致 CPU 使用率飙升。
抛开技术理解不谈,从场景去看这句话的意思是:在初始化过程中,如果某个线程发现它 “丢失了初始化竞争”(即其他线程已经完成了初始化),那么它可以选择 自旋等待(spin),直到初始化完成。再次看完这句话,思考片刻,突然头皮发麻。这不就是我现在的处境吗?在找工作的过程中,如果发现心仪岗位的公司招满了没有了HC(即这个岗位已经完全饱和了),那么我可以选择继续学习等待新的机会,直至找到心仪的岗位为止。
思维切换,从哲学视角去看待:做与不做的影响(争锁与不争锁的影响)
- 行动:通过行动,我们改变了世界的状态,创造了新的可能性。
- 不行动:通过不行动,我们保留了现状,但也可能错失机会或导致问题的积累。
也就是
- 做(竞争锁):线程尝试获取锁,可能会成功并继续执行,也可能会失败并进入阻塞或自旋状态。
- 不做(不竞争锁):线程放弃竞争,可能会导致任务无法完成,或者选择其他路径(如重试、放弃任务等)。
从中不难看出来:
- 竞争的本质:锁竞争反映了资源有限性和需求的冲突。多个线程竞争同一把锁,这不就是现实世界中多人竞争同一份工作吗?
- 自旋锁的哲学意义:自旋锁体现了一种 平衡 的哲学思想。它既不放弃竞争(避免错失机会),也不过度投入(避免资源浪费)。
多年以前,在上初中的时候,就听说过中庸,时至今日,没想到在学习并发锁的知识上,悟出了 中庸之道。
- 作者:fntp
- 链接:https://polofox.com/article/sck-lock
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章