Java synchronized案例怎么用:从入门到实战的完整指南
目录导读
- synchronized核心概念速览
- 基础用法案例:同步方法与同步块
- 经典实战:多线程卖票系统
- 进阶陷阱:错误使用案例与修正
- 性能对比:synchronized vs Lock
- 常见问答FAQ
- 总结与最佳实践
synchronized核心概念速览
Q: synchronized到底锁的是什么?
A: 锁的是对象实例或Class对象。

- 修饰实例方法:锁当前实例
this - 修饰静态方法:锁当前类的
Class对象 - 修饰代码块:锁括号内指定的对象
关键原则:多个线程必须竞争同一把锁才能实现互斥,如果锁不同,synchronized将失效。
基础用法案例:同步方法与同步块
案例1:同步实例方法
public class Counter {
private int count = 0;
public synchronized void increment() { count++; }
// 等价于 synchronized(this) { count++; }
}
适用场景:整个方法都需要同步,且锁对象明确。
案例2:同步静态方法
public class StaticCounter {
private static int count = 0;
public static synchronized void increment() { count++; }
// 锁Class对象,所有实例共享同一把锁
}
案例3:同步代码块(精准锁定)
public class FineGrainedLock {
private final Object lock = new Object();
public void method() {
// 非同步代码...
synchronized (lock) {
// 仅同步临界区代码
}
}
}
优势:缩小同步范围,提升并发性能。
经典实战:多线程卖票系统
问题描述
模拟3个窗口同时卖100张票,要求:
- 不能超卖(同一张票不能卖两次)
- 最终剩余票数为0
错误实现(线程不安全)
class Ticket {
private int tickets = 100;
public void sell() {
if (tickets > 0) {
try { Thread.sleep(10); } catch (InterruptedException e) {}
tickets--;
}
}
}
// 3个线程各卖100次,结果剩余票数可能为负数
正确实现(synchronized锁实例)
class SafeTicket {
private int tickets = 100;
public synchronized void sell() { // 锁this
if (tickets > 0) {
try { Thread.sleep(10); } catch (InterruptedException e) {}
tickets--;
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
SafeTicket ticket = new SafeTicket();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
while (ticket.available() > 0) {
ticket.sell();
}
}).start();
}
}
}
运行结果:剩余票数始终为0,无负数。
注意事项
- 锁必须一致:若使用
SafeTicket的不同实例,锁失效 - 避免在锁内执行耗时I/O:会阻塞其他线程
进阶陷阱:错误使用案例与修正
陷阱1:锁字符串常量
// 错误:字符串常量池导致不同对象共享同一锁
synchronized ("LOCK") { ... }
// 修正:使用new Object()或指定唯一对象
private final Object lock = new Object();
synchronized (lock) { ... }
陷阱2:锁Integer等包装类
// 错误:Integer缓存池(-128~127)导致锁范围扩大
Integer lock = 1;
synchronized (lock) { ... }
// 修正:使用最终常量或专用锁对象
private final Object lock = new Object();
陷阱3:synchronized与非同步混用
class Data {
private int value;
public synchronized void set(int v) { value = v; }
public int get() { return value; } // 未同步!导致读取脏数据
}
// 修正:读取方法也要同步,或使用volatile+原子类
性能对比:synchronized vs Lock
| 特性 | synchronized | Lock (ReentrantLock) |
|---|---|---|
| 锁获取方式 | 隐式 | 显式lock()/unlock() |
| 可中断性 | 不支持 | 支持lockInterruptibly() |
| 公平锁 | 非公平 | 可选公平/非公平 |
| 性能 | 低竞争下优于Lock | 高竞争下更稳定 |
| 语法简洁 | 自动释放锁 | 必须finally解锁 |
何时用synchronized:
- 同步块简单,无需高级特性
- 代码可读性优先
- 低并发场景
何时用Lock:
- 需要超时、可中断、尝试获取锁
- 需要公平锁
- 高并发写场景
常见问答FAQ
Q1:synchronized能锁住int吗?
A:不能,synchronized只能锁对象,int是原始类型,需用Integer包装类,但注意缓存陷阱。
Q2:静态方法用synchronized锁类,会影响实例方法吗?
A:不会,实例方法锁this,静态方法锁Class,两者互不干扰。
Q3:synchronized遇到异常会释放锁吗?
A:会,JVM自动释放锁,即使发生异常或return。
Q4:多个synchronized方法嵌套是否会导致死锁?
A:可能,例如A线程锁obj1请求obj2,B线程锁obj2请求obj1,解决方案:全局排序锁顺序。
Q5:String作为锁对象是否安全?
A:不安全,字符串常量池导致不同线程可能持有相同锁对象,用new Object()确保唯一性。
总结与最佳实践
核心原则
- 锁对象唯一:避免使用字符串常量、Integer缓存
- 锁定范围最小:能用同步块不用方法,能用代码块不用全方法
- 锁内的操作尽量轻量:避免I/O、网络请求等耗时操作
- 使用专用锁对象:声明为
private final Object,避免外部干扰
代码模板
public class ThreadSafeService {
private final Object lock = new Object();
private final Map<String, String> cache = new HashMap<>();
public String getData(String key) {
// 非同步预处理
synchronized (lock) {
// 1. 检查缓存
if (cache.containsKey(key)) return cache.get(key);
// 2. 计算数据(耗时操作)
String result = computeExpensive(key);
// 3. 放入缓存
cache.put(key, result);
return result;
}
}
}
避坑清单
- [x] 锁是否可能为
null? - [x] 是否存在字符串常量池风险?
- [x] 锁内的代码是否可能长时间阻塞?
- [x] 是否所有写操作都加了同步?
- [x] 读取操作是否需要同步保证可见性?
通过本文的案例和陷阱分析,你应该能从容应对90%的Java同步开发场景。简单问题用synchronized,复杂场景用Lock,选对工具事半功倍。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播