Java方法同步与成员锁同步的并发访问安全问题
关于Java synchronized实例方法的互斥范围解答
首先明确核心结论:
- synchronized修饰的实例方法,持有的锁是当前对象实例本身(也就是示例中Thing类的实例对象,不是它的成员变量),它的互斥范围仅针对所有同样以该Thing实例为锁对象的同步代码块/同步方法,和锁其他对象(比如它的内部成员innerThing)的同步逻辑完全无关。
你给出的示例代码中,foo()和bar()并发调用一定会出现数据竞争,原因如下:
- 执行
synchronized void foo()时,线程获取的是this(当前Thing实例)的锁 - 执行
bar()里的synchronized(innerThing)时,线程获取的是innerThing这个成员对象的锁 - 两个锁是完全独立的不同对象,不存在互斥关系,两个线程可以同时进入各自的同步块执行
innerThing.mutate(),如果mutate()方法里有非原子的修改操作,就会触发数据竞争。
额外提醒:Java的同步机制完全是基于锁对象的匹配来实现互斥的,没有任何隐式的“锁了外层对象就自动保护它所有成员”的语义,只要两个同步逻辑持有的锁对象不是同一个,就不会产生互斥效果。如果要让foo和bar互斥,只要保证两者的锁对象一致即可。
如果要修复示例的数据竞争问题,可选两种修改方案:
第一种,bar也锁当前Thing实例:
public void bar() { synchronized(this) { innerThing.mutate(); } }
第二种,foo也锁innerThing实例:
public void foo() { synchronized(innerThing) { innerThing.mutate(); } }
内容的提问来源于stack exchange,提问作者aspen100
相关产品推荐
相关产品推荐

