在Java多线程编程中,当多个线程并发访问同一个共享变量或资源时,可能会产生竞态条件,导致数据不一致。synchronized是Java提供的内置同步机制,能够通过加锁保证同一时间只有一个线程执行被保护的代码,从而实现线程安全。

一、synchronized的三种使用方式
synchronized可以修饰实例方法、静态方法和代码块,不同位置对应的锁对象不同。
1. 修饰实例方法
锁对象是当前实例(this),同一实例的同步方法同一时刻只能被一个线程访问。
public class Counter {
private int count = 0;
// 修饰实例方法,锁为this
public synchronized void increment() {
count++; // 线程安全地自增
}
public synchronized int getCount() {
return count;
}
}
2. 修饰静态方法
锁对象是当前类的Class对象,控制该类所有实例的并发访问。
public class StaticCounter {
private static int count = 0;
// 修饰静态方法,锁为StaticCounter.class
public static synchronized void increment() {
count++;
}
}
3. 修饰同步代码块
可以显式指定锁对象,粒度更细,减少锁持有时间,提升性能。
public class BlockDemo {
private final Object lock = new Object();
private int value = 0;
public void update(int v) {
// 只同步修改共享变量的部分
synchronized (lock) {
value = v;
}
}
}
二、底层实现与监视器锁
synchronized基于对象头的监视器锁(monitor)实现。线程进入同步块前必须获取锁,退出时释放锁。在JDK 1.6之后,锁存在偏向锁、轻量级锁和重量级锁的升级过程,减少无竞争时的开销。
| 锁状态 | 适用场景 |
|---|---|
| 偏向锁 | 只有一个线程访问同步块 |
| 轻量级锁 | 多线程交替访问,无实际竞争 |
| 重量级锁 | 多线程激烈竞争,线程阻塞 |
三、使用注意点
- 锁对象建议使用私有不可变对象,避免锁被外部修改。
- 不要将String常量或基础类型包装类作为锁,可能引发意外共享。
- 同步范围不宜过大,否则会降低并发度。
- synchronized不能跨方法或跨JVM保证原子性,分布式环境需使用分布式锁。
四、简单示例验证
下面用两个线程同时调用increment,验证synchronized的线程安全效果。
public class Test {
public static void main(String[] args) throws InterruptedException {
Counter c = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
c.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(c.getCount()); // 输出2000,结果正确
}
}
通过上述方式,Java使用synchronized以监视器锁为核心,配合不同粒度的用法,能够可靠地保证线程安全。理解其实现与限制,是编写稳健并发程序的基础。
synchronized线程安全Java同步机制修改时间:2026-07-27 05:45:16