Java 锁入门指南(通俗易懂版)
·
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):常用同步方法
更多推荐


所有评论(0)