对象锁不共享、不互通,每个实例拥有独立锁;多线程操作不同对象实例的同步方法不会阻塞,仅操作同一实例时才竞争锁;误用导致超卖等问题,应改用类锁、共享锁对象或并发工具类。

对象锁在多实例环境下**不共享、不互通**,每个实例拥有独立的锁。这意味着:多个线程操作不同对象实例时,即使调用的是同一个同步方法,也不会相互阻塞。
对象锁的本质是“每实例一把锁”
Java 中每个对象(即每个 new 出来的实例)都有自己的内置监视器(monitor),synchronized 修饰的实例方法或 synchronized(this) 代码块,锁的就是当前对象实例(this)。因此:
- 两个
new TicketDemo1()创建的对象 A 和 B,各自有独立的对象锁; - 线程 T1 调用 A.sellInstanceTicket(),获取的是 A 的锁;
- 线程 T2 同时调用 B.sellInstanceTicket(),获取的是 B 的锁 —— 二者互不影响,可并发执行;
- 只有当多个线程操作**同一个对象实例**时,才会因争夺同一把锁而排队等待。
典型陷阱:误以为 synchronized 方法 = 全局互斥
常见错误是给实例方法加 synchronized,却创建了多个对象供多线程使用,结果出现超卖、计数错乱等问题。例如:
- 抢票系统中,若每个线程都 new 一个
TicketSeller实例,sell()再同步也无效; - 真正需要保护的是共享的票数变量(如
static int tickets或单例状态),而不是每个对象的私有字段; - 此时应改用类锁(
synchronized(TicketSeller.class))或共享锁对象(private static final Object LOCK = new Object())。
验证方式:观察线程是否阻塞
可通过以下方式判断是否真正在竞争同一把对象锁:
立即学习“Java免费学习笔记(深入)”;
- 打印线程名 + 锁对象的哈希值:
System.out.println("Lock obj: " + System.identityHashCode(this));; - 用
jstack查看线程堆栈,若多个线程处于BLOCKED (on object monitor)状态且等待同一对象地址,则说明在争抢同一把锁; - 对比单实例 vs 多实例场景下输出的顺序和数值一致性(如票数是否减为负值)。
正确应对多实例共享资源的策略
当业务逻辑涉及多个对象实例但需保护同一份数据时,不能依赖 this 锁,而应显式指定共享锁目标:
- 用
private static final Object SHARED_LOCK = new Object();作为统一锁对象; - 对静态资源加类锁:
synchronized (MyClass.class) { ... }; - 将共享状态抽离为单例服务,由该服务内部控制同步;
- 优先考虑
java.util.concurrent原子类(如AtomicInteger)或线程安全集合,减少显式锁开销。


















