synchronized 是 Java 中用于解决多线程并发问题最基本、最常用的工具,它是一种内置锁(也称为监视器锁或互斥锁),能够确保在同一时刻,只有一个线程可以执行被 synchronized 修饰的代码块或方法,从而保证了线程安全。

synchronized 的核心作用
- 原子性:确保一个代码块或方法的操作是不可分割的,一个线程一旦开始执行,就必须执行完毕,中间不会被其他线程打断。
- 可见性:当一个线程释放锁时,它在该临界区内对共享变量的所有修改都会被刷新到主内存中,当另一个线程获取同一个锁时,它会从主内存中读取这些共享变量,从而保证了线程间的可见性。
- 有序性:
synchronized会禁止指令重排序,保证了代码的执行顺序与代码的编写顺序一致。
synchronized 的三种使用方式
synchronized 可以用在三个地方:实例方法、静态方法和代码块。
synchronized 实例方法
当 synchronized 修饰一个非静态(实例)方法时,锁是当前对象实例(this)。
语法:
public synchronized void instanceMethod() {
// 临界区代码
}
工作原理:

- 假设有两个线程
Thread-A和Thread-B,它们都调用了同一个对象myObject的instanceMethod()方法。 - 当
Thread-A调用时,它会获取myObject这个对象的锁。 - 在
Thread-A执行完方法并释放锁之前,Thread-B如果也想调用myObject的instanceMethod(),它必须等待,因为myObject的锁已经被Thread-A占用了。 - 注意:
Thread-B调用的是myObject2(另一个不同的对象实例)的instanceMethod(),那么它不需要等待,因为它们锁的是不同的对象。
示例:
class Counter {
private int count = 0;
// 锁是 this 对象
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount()); // 输出应为 2000
}
}
synchronized 静态方法
当 synchronized 修饰一个静态方法时,锁是当前类的 Class 对象(MyClass.class)。
语法:
public static synchronized void staticMethod() {
// 临界区代码
}
工作原理:

- 这个锁属于类级别,而不是对象级别。
- 无论有多少个该类的对象实例,对于这个静态方法的锁都是同一个——
Class对象。 - 当一个线程访问
obj1.staticMethod()时,另一个线程访问obj2.staticMethod()(obj1和obj2是同一个类的不同实例)时,它们会互相等待,因为它们竞争的是同一个Class对象的锁。
示例:
class SharedResource {
// 锁是 SharedResource.class 对象
public static synchronized void staticOperation() {
System.out.println(Thread.currentThread().getName() + " is in staticOperation.");
try {
Thread.sleep(2000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is leaving staticOperation.");
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() -> SharedResource.staticOperation(), "Thread-1");
Thread t2 = new Thread(() -> SharedResource.staticOperation(), "Thread-2");
t1.start();
t2.start();
}
}
预期输出:Thread-1 会先进入,执行2秒后退出,Thread-2 才能进入,它们不会并行执行。
synchronized 代码块
这是最灵活、最常用的一种方式,它可以指定锁对象,从而只锁定代码中真正需要同步的部分,而不是整个方法,提高了并发度。
语法:
// 锁是任意对象
synchronized (lockObject) {
// 临界区代码
}
工作原理:
lockObject可以是任何对象,但必须是同一个对象才能起到互斥作用。- 我们会使用一个专门用于加锁的
private final Object,以避免外部代码意外修改锁对象。 - 如果锁对象是
this,那么效果等同于synchronized实例方法。 - 如果锁对象是
ClassName.class,那么效果等同于synchronized静态方法。
示例:
class CounterWithBlock {
private int count = 0;
// 创建一个专用的锁对象
private final Object lock = new Object();
public void increment() {
// 只对需要同步的代码块加锁
synchronized (lock) {
count++;
}
// 这里的代码不需要同步,可以和其他线程并行执行
// ... some other non-critical code ...
}
// 等价于 synchronized (this) 的写法
public void anotherIncrement() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
优点:
- 粒度更细:只锁定必要的代码,减少锁的持有时间,提高性能。
- 灵活性高:可以选择任意对象作为锁,实现更复杂的同步逻辑。
synchronized 的底层原理
synchronized 的底层实现依赖于 JVM 的 Monitor(监视器)机制。
-
对象头:在 Java 中,每个对象在内存中都有对象头,对象头里存储了对象的运行时数据(如哈希码、GC分代年龄)和类型指针,更重要的是,它还包含一个指向Monitor的指针。
-
Monitor:可以理解为一个同步工具或一个同步对象,每个对象都可以关联一个 Monitor。
- 当一个线程想要进入被
synchronized保护的代码块时,它必须先获取与对象关联的 Monitor 的所有权。 - Monitor 内部有一个计数器(
_count)和一个等待队列(_WaitSet)。 - 获取锁:
_count为 0,表示 Monitor 没有被占用,线程将_count设为 1,成功获取锁。_count不为 0,说明已经有线程持有了锁,该线程就会被放入_WaitSet中进行阻塞等待。 - 释放锁:持有锁的线程执行完毕后,会将
_count减 1,当_count减为 0 时,表示锁被释放,JVM 会从_WaitSet中唤醒一个线程去尝试获取锁。
- 当一个线程想要进入被
-
锁升级(JDK 1.6 优化): 为了提升性能,JVM 对
synchronized做了大量优化,引入了锁升级的概念:- 偏向锁:假设一个锁总是由同一个线程获取,当一个线程获取锁时,JVM 会将锁的“偏向”设置给该线程,之后该线程再获取锁时,就不需要进行 CAS(Compare-And-Swap)操作了,开销极小。
- 轻量级锁:当有另一个线程竞争锁时,偏向锁会升级为轻量级锁,竞争线程会通过自旋(忙等待)的方式尝试获取锁,而不是立即阻塞,自旋可以避免线程切换的开销。
- 重量级锁:如果自旋一定次数后仍然没有获取到锁,或者有更多线程竞争,轻量级锁就会升级为重量级锁,未获取到锁的线程会被阻塞,并进入操作系统内核态的等待队列,等待操作系统来唤醒。
这个锁升级的过程是自动的,旨在让 synchronized 在不同场景下都能有较好的性能。
synchronized 的优缺点
优点:
- 使用简单:语法直观,易于理解和实现。
- 非阻塞同步:在竞争不激烈的情况下,经过优化的
synchronized(偏向锁、轻量级锁)性能非常高,接近于无锁。 - 保证可见性:J
