题目
请解释Java中synchronized关键字的用途,并说明它可以应用在哪些地方?
信息
- 类型:问答
- 难度:⭐
考点
synchronized关键字,线程同步,锁机制
快速回答
synchronized关键字用于解决多线程环境下的数据竞争问题,主要用途是:
- 确保同一时刻只有一个线程能访问被保护的代码块或方法
- 保证线程对共享资源操作的可见性和原子性
应用位置:
- 实例方法:锁定当前对象实例
- 静态方法:锁定当前类的Class对象
- 代码块:可指定任意对象作为锁
一、核心原理
synchronized是Java内置的互斥锁机制,通过对象监视器(Monitor)实现:
- 当线程进入synchronized区域时,自动获取锁
- 其他线程尝试获取同一锁时会被阻塞
- 线程执行完同步代码后自动释放锁
二、代码示例
// 1. 实例方法同步
class Counter {
private int count = 0;
public synchronized void increment() {
count++; // 线程安全操作
}
}
// 2. 静态方法同步
class Logger {
public static synchronized void log(String msg) {
System.out.println(msg);
}
}
// 3. 同步代码块
class SafeList {
private final List<String> list = new ArrayList<>();
private final Object lock = new Object();
public void add(String item) {
synchronized (lock) { // 显式指定锁对象
list.add(item);
}
}
}三、最佳实践
- 减小同步范围:优先使用代码块而非整个方法
- 避免锁嵌套:防止死锁(如线程A持有锁1请求锁2,线程B持有锁2请求锁1)
- 使用final对象锁:防止锁对象被意外修改
- 替代方案:简单场景可用
java.util.concurrent.atomic包下的原子类
四、常见错误
- 错误1:同步不同对象
示例:synchronized(new Object()){...}(每次锁不同对象) - 错误2:误用字符串常量锁
示例:synchronized("LOCK")(可能与其他代码意外互斥) - 错误3:忘记同步setter/getter
示例:非同步的get方法可能读到未完全构造的对象
五、扩展知识
- 锁升级机制:JDK6后优化为偏向锁→轻量级锁→重量级锁
- 与ReentrantLock对比:synchronized更简单,ReentrantLock支持公平锁和条件变量
- happens-before原则:synchronized保证解锁前的操作对加锁线程可见