Skip to content

Java Lock

🧩 一、什么是“锁”?

锁(Lock)是多线程并发编程中用来控制共享资源访问的机制

核心目标: 防止多个线程同时修改同一个数据,导致数据不一致(线程安全问题)。


🎯 举个生活例子:

假设你和别人共用一个文件夹(共享资源),

  • 没有锁:你们同时修改文件 → 文件损坏
  • 加锁:一个人编辑时上锁,别人必须等你完成再操作

这就是“锁”的直观意义。


⚙️ 二、Java 中锁的几种体现形式

Java 从语法层面到类库层面,有多种锁机制:

层级锁机制说明
语法级synchronized最常用关键字,隐式锁
API级java.util.concurrent.locks.Lock显式锁(如 ReentrantLock
原子类java.util.concurrent.atomic.*基于 CAS 的无锁机制(乐观锁思想)

我们分别看看。


🧱 1️⃣ synchronized —— 内置锁(Monitor)

synchronized 是最经典的同步机制。 用法简单,例如:

java
synchronized (obj) {
    // 临界区
}

它底层依赖的是 对象头中的 Monitor 锁(监视器锁), 属于 “悲观锁”(下面会解释)。

在方法上也可以加:

java
public synchronized void add() { ... }

Java 编译器在字节码中会生成 monitorentermonitorexit 指令。


⚙️ 2️⃣ Lock 接口及其实现类(显式锁)

JDK 1.5 引入了 java.util.concurrent.locks.Lock 接口,更灵活:

java
Lock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区
} finally {
    lock.unlock();
}

优点:

  • 可以尝试获取锁(tryLock()
  • 可中断获取锁(lockInterruptibly()
  • 可以实现公平锁 / 非公平锁

这种锁在功能上比 synchronized 更强,底层通常也基于 AQS(AbstractQueuedSynchronizer)。


💡 3️⃣ CAS(Compare-And-Swap)与原子类

CAS 是无锁机制(lock-free),它是“乐观锁”的基础。

比如:

java
AtomicInteger i = new AtomicInteger(0);
i.incrementAndGet(); // 内部用CAS实现

CAS 是一种硬件级原子指令, 会比较“内存中旧值”和“期望值”,如果相等才更新,否则重试。


🧠 三、锁的分类(重要!!)

在理解 Java 锁机制时,我们经常听到:

悲观锁 / 乐观锁 公平锁 / 非公平锁 可重入锁 / 不可重入锁 读写锁 / 独占锁 自旋锁 等

我们来一一梳理清楚:


🔒 1️⃣ 悲观锁(Pessimistic Lock)

  • 认为“竞争一定会发生”,所以先上锁再操作
  • 典型代表:synchronized, ReentrantLock

示例:

java
synchronized (this) {
    count++;
}

执行时会让其他线程等待锁释放。 特点是:安全但可能慢


😊 2️⃣ 乐观锁(Optimistic Lock)

  • 认为“冲突是少数情况”,所以不加锁,先操作再检查
  • 如果发现冲突,再重试。

实现方式:CAS(Compare-And-Swap)

示例(简化):

java
while (true) {
    int oldValue = atomicInt.get();
    int newValue = oldValue + 1;
    if (atomicInt.compareAndSet(oldValue, newValue)) {
        break; // 成功
    }
    // 否则重试
}

优点:高性能(无锁) 缺点:竞争激烈时重试多,CPU 占用高。


🧭 3️⃣ 公平锁 vs 非公平锁

  • 公平锁:按照线程申请锁的顺序获取锁。
  • 非公平锁:允许“插队”,效率更高。

ReentrantLock 默认是非公平的,但可以指定:

java
new ReentrantLock(true); // 公平锁

🔁 4️⃣ 可重入锁(Reentrant Lock)

同一个线程多次获取同一把锁不会死锁。 例如:

java
public synchronized void a() {
    b(); // 再次进入同一锁
}
public synchronized void b() { }

synchronizedReentrantLock 都是可重入锁。


📚 5️⃣ 读写锁(ReadWriteLock)

当读操作远多于写操作时,为了提高并发度:

  • 多个线程可以同时读(不冲突)
  • 写时独占
java
ReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock();
...
rwLock.writeLock().lock();

🔁 6️⃣ 自旋锁(Spin Lock)

线程在等待锁时,不挂起,而是循环检查锁状态。 在竞争不激烈的情况下可以减少上下文切换。

Java 的 CAS 实现就体现了这种“自旋”思想。


📊 四、这些锁的关系与演化(总结图)

锁的层级:
┌─────────────────────────────┐
│ synchronized (悲观锁,内置锁) │
│ ReentrantLock (显式锁,可重入) │
│ ReadWriteLock (细粒度锁)     │
│                              │
│ → AQS (底层实现框架)          │
│ → CAS (底层硬件指令)          │
└─────────────────────────────┘

         └─ 乐观锁思想(基于CAS)

⚡ 五、总结一句话记忆:

类型特点代表实现
悲观锁先锁后干,防冲突synchronized, ReentrantLock
乐观锁干完再比对,冲突重试AtomicInteger, CAS
公平锁排队执行ReentrantLock(true)
非公平锁插队执行ReentrantLock(false)
可重入锁同一线程可重复加锁synchronized, ReentrantLock
读写锁读并发、写独占ReentrantReadWriteLock

随便写写的,喜欢就好。 使用VitePress构建