Java synchronized 关键字详解
一、核心概念
synchonized (certificate) {...}
是 Java 中的一个同步代码块,用于控制多线程对共享资源的访问,防止并发问题。
核心含义:进入这个代码块之前,必须先获得
certificate
对象的锁,确保同一时刻只有一个线程能执行这段代码。
这是 Java 实现线程安全的核心机制之一。
二、语法结构
synchronized (对象) {// 需要同步执行的代码
}
synchronized
:Java 关键字,表示"同步"(certificate)
:锁对象,也叫"监视器(Monitor)"{}
中的代码:临界区(Critical Section),同一时间只能被一个线程执行
三、锁对象机制
certificate
是一个对象实例(如 Certificate certificate = new Certificate();
)。
在 Java 中:
任何一个对象都可以作为"锁",因为每个对象都有一个内置的"监视器锁"(Monitor Lock)。
工作原理:
- 当线程 A 进入
synchronized (certificate)
时,尝试获取certificate
对象的锁 - 如果获取成功,就执行代码块
- 如果另一个线程 B 也想进入,但锁被 A 占着,B 就会被阻塞,直到 A 执行完并释放锁
四、生活化比喻
将 certificate
比作公共厕所的钥匙:
- 多个线程像多个想上厕所的人
- 只有一把钥匙(
certificate
) - 谁拿到钥匙(获得锁),谁才能进去(执行代码)
- 别人必须等他出来(释放锁)后才能拿钥匙进去
这就是 synchronized
的核心思想:互斥访问。
五、代码示例
public class CertificateService {private Certificate certificate = new Certificate(); // 共享资源public void updateCertificate() {synchronized (certificate) {// 模拟对 certificate 的修改System.out.println("线程 " + Thread.currentThread().getName() + " 开始修改证书");certificate.setName("新证书");certificate.setValid(true);try {Thread.sleep(2000); // 模拟耗时操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程 " + Thread.currentThread().getName() + " 修改完成");}// 锁在这里自动释放}
}
执行结果:线程串行执行,不会出现数据竞争
线程-1 开始修改证书
(等待 2 秒)
线程-1 修改完成线程-2 开始修改证书
(等待 2 秒)
线程-2 修改完成
六、注意事项
1. 锁的对象必须是同一个
synchronized (new Certificate()) { ... } // 每次 new,锁不同,无效!
必须是同一个实例,如:
- 成员变量
certificate
this
(当前对象)String.class
(类锁)
2. 锁的粒度要合适
- 锁的范围太大 → 性能差(串行化)
- 锁的范围太小 → 可能漏掉需要保护的代码
3. 避免死锁
不要嵌套多个 synchronized
,尤其是不同对象的锁。
七、与其他同步方式对比
写法 | 锁对象 | 说明 |
---|---|---|
synchronized void f() | this (当前实例) | 锁整个方法 |
synchronized (obj) | obj (指定对象) | 锁更小范围,更灵活 ✅ 推荐 |
synchronized (certificate)
比synchronized
方法更精细。
八、适用场景
当有共享资源被多个线程访问时使用:
- 修改用户状态
- 更新库存
- 写日志文件
- 操作缓存
九、总结
问题 | 回答 |
---|---|
synchronized (certificate) 是什么? | 同步代码块,确保线程安全 |
certificate 是锁吗? | 是,任何对象都可以作为锁 |
作用是什么? | 防止多个线程同时修改共享资源 |
什么时候用? | 多线程环境下操作共享数据 |
有什么风险? | 性能下降、死锁(需谨慎使用) |
最终结论
synchronized (certificate)
是 Java 中实现线程安全的重要手段。它通过"对象锁"机制,确保同一时刻只有一个线程能执行关键代码,避免数据竞争和不一致。
记住:"谁拿锁,谁执行;别人等着!"