synchronized修饰实例方法时锁的是当前对象(this),同一对象的多线程调用会串行执行,不同对象则互不影响;需注意锁粒度、避免this重赋值、统一锁对象,并在必要时选用reentrantlock。

synchronized 修饰实例方法时,锁的是当前对象(this),也就是调用该方法的对象实例。多个线程同时访问同一个对象的 synchronized 实例方法时,会被强制串行执行;但若访问的是不同对象的同一方法,则互不影响——因为锁的对象不同。
一、synchronized实例方法的锁对象是this
当一个方法被声明为 public synchronized void doSomething(),等价于:
public void doSomething() { synchronized(this) { /* 方法体 */ } }
这意味着:只有持有当前对象监视器(monitor)的线程才能进入该方法。其他线程若尝试调用同一对象的该方法,必须等待前一个线程释放锁。
二、同一对象多线程调用会阻塞,不同对象则不干扰
假设有一个计数器类:
class Counter {
private int count = 0;
public synchronized void increment() { count++; }
public int getCount() { return count; }
}
测试场景:
- 两个线程都调用
counter1.increment()→ 线程安全,结果准确 - 一个线程调用
counter1.increment(),另一个调用counter2.increment()(counter1 != counter2)→ 不争抢同一把锁,各自独立执行
三、注意避免锁粒度不当或误用
常见误区和建议:
- 不要在方法内部对
this重新赋值,否则可能破坏锁语义(虽然编译允许,但逻辑危险) - 如果需要保护多个方法共享的状态,确保所有相关操作都用同一个锁(即都用 synchronized 实例方法,或统一用 synchronized(this) 块)
- 避免在 synchronized 方法中调用外部可变对象的同步方法(如 I/O、网络、第三方库),以防锁被长时间占用,影响并发性能
- 若需更灵活的锁控制(如尝试获取、超时、可中断),考虑使用
java.util.concurrent.locks.ReentrantLock
四、简单验证示例
可运行代码片段:
Counter c = new Counter();
Thread t1 = new Thread(() -> { for(int i=0; iThread t2 = new Thread(() -> { for(int i=0; it1.start(); t2.start();
t1.join(); t2.join();
System.out.println(c.getCount()); // 输出应为 2000
若去掉 synchronized,大概率输出小于 2000(存在竞态条件)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











