**synchronized**
是 Java 中的一个关键字,用于实现线程同步,确保多个线程在访问共享资源时的线程安全。它的主要作用是防止多个线程同时执行某个代码块或方法,从而避免数据不一致或竞态条件(Race Condition)的问题。
synchronized 的作用
- 线程安全:确保同一时间只有一个线程可以访问被
synchronized
修饰的代码块或方法。 - 可见性:保证线程对共享变量的修改对其他线程是可见的(通过内存屏障实现)。
- 原子性:确保被
synchronized
保护的代码块或方法是一个不可分割的操作。
synchronized 的用法
synchronized
可以用于以下两种场景:
1. 修饰实例方法
- 锁对象是当前实例(
this
)。 - 同一时间只有一个线程可以执行该实例的
synchronized
方法。
public class Counter {
private int count = 0;
// synchronized 修饰实例方法
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
解释:
- 多个线程调用同一个
Counter
实例的increment()
方法时,只有一个线程可以执行该方法,其他线程需要等待。
2. 修饰静态方法
- 锁对象是当前类的
Class
对象(Counter.class
)。 - 同一时间只有一个线程可以执行该类的
synchronized
静态方法。
public class Counter {
private static int count = 0;
// synchronized 修饰静态方法
public static synchronized void increment() {
count++;
}
public static int getCount() {
return count;
}
}
解释:
- 多个线程调用
Counter.increment()
时,只有一个线程可以执行该方法,其他线程需要等待。
3. 修饰代码块
- 可以指定锁对象(可以是任意对象)。
- 更细粒度的控制,减少锁的竞争。
public class Counter {
private int count = 0;
private final Object lock = new Object(); // 锁对象
public void increment() {
// synchronized 修饰代码块
synchronized (lock) {
count++;
}
}
public int getCount() {
return count;
}
}
解释:
- 只有获取到
lock
对象的线程才能执行synchronized
代码块中的内容。
synchronized 的工作原理
- 锁机制:
- 每个 Java 对象都有一个内置锁(Monitor Lock),也称为监视器锁。
- 当一个线程进入
synchronized
代码块或方法时,它会尝试获取锁;如果锁已被其他线程持有,则当前线程进入阻塞状态,直到锁被释放。
- 锁的释放:
- 当线程执行完
synchronized
代码块或方法后,会自动释放锁。 - 即使代码块中抛出异常,锁也会被释放。
- 当线程执行完
synchronized 的优缺点
优点
- 简单易用:Java 语言原生支持,无需额外依赖。
- 自动管理锁的获取和释放,避免死锁(在正确使用的情况下)。
缺点
- 性能开销:线程竞争锁时会导致上下文切换和阻塞,影响性能。
- 粒度较粗:如果锁的范围过大,可能会导致并发性能下降。
synchronized 与其他锁机制的对比
特性 | synchronized | ReentrantLock |
---|---|---|
锁类型 | 内置锁(JVM 实现) | 显式锁(Java 代码实现) |
灵活性 | 较低 | 较高(支持公平锁、可中断锁等) |
性能 | 在低竞争场景下性能较好 | 在高竞争场景下性能较好 |
锁释放 | 自动释放 | 需要手动调用 unlock() |
示例:synchronized 的实际应用
以下是一个使用 synchronized
实现线程安全的计数器:
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedExample example = new SynchronizedExample();
// 创建多个线程并发调用 increment()
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + example.getCount()); // 输出 2000
}
}
解释:
- 两个线程并发调用
increment()
方法,但由于synchronized
的保护,最终结果是正确的(2000)。
总结
synchronized
是 Java 中实现线程同步的基本工具。- 它通过锁机制确保线程安全,但需要注意锁的粒度和性能开销。
- 在高并发场景下,可以考虑使用
ReentrantLock
等更灵活的锁机制。