Java 锁入门指南(通俗易懂版)

如果你第一次接触 Java 的“锁”,这篇就是为你准备的。


什么是锁?(最通俗的解释)

想象你们办公室只有 一台打印机
很多人想用,但是:

  • 同一时刻只能一个人打印
    这就是 互斥锁
  • 可以很多人同时读说明书
    这就是 读锁共享
  • 但有人正在修改说明书(写)
    其他人不能读或写
    这就是 写锁独占

所以:
锁 = 控制多个线程(人)访问同一资源(打印机、文件等)时不会打架的工具。


Java 有哪些锁?

你只需要记住下面三类:

1. synchronized(最简单,语言内置)
2. Lock(JUC 提供,功能更强)
3. 并发工具类里的高级锁(Semaphore 等)

我下面会一类一类讲,超级简单 + 带例子。


1. synchronized(最简单的锁)

小白最先学的锁,它写法简单,JVM 自动帮你管理。

作用

保证同一时刻只有一个线程执行某段代码。

使用方式(顺序从最常见到最少见)


示例 1:锁方法

public synchronized void print() {
    System.out.println("正在打印...");
}

就像房门上锁,只允许一个线程进来执行这方法。


示例 2:锁代码块

public void print() {
    synchronized (this) { // this 就是锁
        System.out.println("正在打印...");
    }
}

效果跟锁方法一样,只是把锁的范围缩小了。


示例 3:锁类(静态锁)

public static synchronized void print() {
    System.out.println("全局打印器");
}

这是全局锁,全项目(整个类)范围内有效。


特点总结

特点通俗解释
可重入自己锁门自己还能进,不会被自己拦住
自动释放退出 synchronized 会自动解锁,不容易写错
用法简单小白最友好


2. ReentrantLock(更强版的锁)

synchronized 是“傻瓜锁”,ReentrantLock 是“专业版锁”。

需要你手动 lock()unlock()


示例:锁住一个代码段

ReentrantLock lock = new ReentrantLock();

public void print() {
    lock.lock(); // 手动上锁
    try {
        System.out.println("打印中...");
    } finally {
        lock.unlock(); // 手动解锁(必须写)
    }
}

ReentrantLock 有 synchronized 做不到的功能

功能通俗说明
tryLock()尝试拿锁,拿不到就算了,不会傻等
可中断等锁时可以被打断
公平锁按排队顺序拿锁(synchronized 没有)
Condition多个等待队列,好比“多屋子排队”

示例:tryLock()(不阻塞等待)

if (lock.tryLock()) {
    try {
        System.out.println("拿到锁,执行...");
    } finally {
        lock.unlock();
    }
} else {
    System.out.println("没拿到锁,不等了");
}

这在生产环境很常用,比如防止死等。



3. 读写锁:ReentrantReadWriteLock

通俗:
“读可以多人同时看书,写只能一个人改书。”


示例

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();

读锁(多人读)

readLock.lock();
try {
    System.out.println("读数据...");
} finally {
    readLock.unlock();
}

写锁(一个人写)

writeLock.lock();
try {
    System.out.println("写数据...");
} finally {
    writeLock.unlock();
}

为什么读写锁这么牛?

  • 读读不互斥
  • 写写互斥
  • 读写互斥

适合“读多写少”的系统,比如配置中心、缓存。



4. StampedLock(最新更快的锁)

功能更强,适合高性能系统,但不适合新手。

核心特点:

  • 乐观读(非常快,不会阻塞)
  • 悲观读
  • 写锁

先给你个通俗例子:


示例:乐观读

StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead(); // 快速读,不上锁

int x = this.x; // 读数据
int y = this.y;

// 期间如果有人写了,就不能用了
if (!lock.validate(stamp)) {
    // 被写锁干扰了,重新读
    stamp = lock.readLock();
    try {
        x = this.x;
        y = this.y;
    } finally {
        lock.unlockRead(stamp);
    }
}

通俗理解:
“我先快速看一眼(不加锁),如果有人动了,我再认真看(加锁)。”


5. 高级锁(并发工具类)

这些不是传统意义的锁,但常被用作“同步控制”。


Semaphore(信号量)

限制访问资源的“许可证数量”。

例子:停车场只能停 3 辆车。

Semaphore s = new Semaphore(3);

s.acquire(); // 进停车场
System.out.println("停车中...");
s.release(); // 离开

CountDownLatch(倒计时锁)

比如:
主线程要等 3 个任务全部完成,才能继续。

CountDownLatch latch = new CountDownLatch(3);

new Thread(() -> {
    System.out.println("任务1完成");
    latch.countDown();
}).start();

latch.await(); // 等待全部任务完成
System.out.println("所有任务完成,继续执行");

CyclicBarrier(栅栏)

让一堆线程“一起出发”。

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("全部人都到了,开始行动!");
});

总结(小白都懂)

锁不是高难度技术,本质可以一句话总结:

锁就是防止多个线程同时操作同一份数据导致混乱。

Java 为你准备了三类锁:

1. synchronized:最简单、最适合入门
2. Lock(ReentrantLock、读写锁):更灵活更强
3. 工具类(Semaphore、CountDownLatch):常用同步方法
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐