自旋锁通过volatile变量和while循环实现轻量级加锁,配合Thread.yield()降低CPU占用;加锁时循环尝试CAS获取锁,失败则让出CPU,解锁直接置false;适用于短临界区且多核场景。

可以用 while 循环不断检查锁状态,配合 Thread.yield() 让出 CPU 时间片,避免线程长时间空转占用全部 CPU 资源,从而实现一个轻量级的自旋锁。
核心思路:用 volatile 变量表示锁状态
自旋锁不依赖操作系统互斥量,而是靠一个共享的 volatile boolean 标志位(如 locked)来表示是否被占用。由于 volatile 保证可见性和禁止重排序,多线程能及时看到状态变化。
-
加锁逻辑:循环读取
locked,若为false则尝试用compareAndSet(或同步块+判断)抢占;成功则跳出循环,获得锁 -
未抢到时:调用
Thread.yield(),提示调度器“我暂时让出 CPU”,减少忙等待开销 -
解锁逻辑:直接将
locked设为false(需保证原子性,volatile 写已足够)
基础实现(无 CAS,适合理解原理)
以下是一个简化但可运行的版本(注意:生产环境建议用 AtomicBoolean + compareAndSet 保证原子性):
public class SimpleSpinLock {
private volatile boolean locked = false;
public void lock() {
while (true) {
if (!locked) {
// 尝试获取锁(非原子!仅示意;实际应使用 AtomicBoolean)
if (!locked) { // 二次检查(避免竞态)
locked = true;
return;
}
}
Thread.yield(); // 主动让出时间片
}
}
public void unlock() {
locked = false;
}
}
⚠️ 注意:上面的 locked = true 不是原子操作,在多核下存在竞态风险。真正安全的做法是用 java.util.concurrent.atomic.AtomicBoolean:
private final AtomicBoolean locked = new AtomicBoolean(false);
public void lock() {
while (!locked.compareAndSet(false, true)) {
Thread.yield();
}
}
public void unlock() {
locked.set(false);
}
适用场景与注意事项
自旋锁适合锁持有时间极短(纳秒~微秒级)、且线程数不多于 CPU 核心数的场景,比如高性能队列、底层并发结构内部。
-
别在锁内做耗时操作:否则其他线程会持续
yield等待,浪费调度资源 -
慎用于单核 CPU:
yield()可能让当前线程立刻重新被调度,反而加剧竞争 -
考虑退化策略:长时间自旋后可转为阻塞(如结合
LockSupport.park()),变成混合锁 -
Java 本身不推荐手写:
ReentrantLock在低竞争时会自动优化为类似自旋行为,更可靠
小结:yield 的作用不是“保证让出”,而是“友好提示”
Thread.yield() 不保证当前线程一定暂停,也不保证其他线程立即执行,但它向 JVM 和 OS 调度器表达了“我愿意让出”的意图,有助于降低 CPU 占用率和提升整体吞吐。搭配 volatile 或 Atomic* 类型,就能构建出简单有效的用户态自旋机制。










