关于synchronized保证A对象线程安全的技术咨询
问题
在B类中定义了一个使用synchronized关键字的方法,该方法操作一个公开可用的A类对象。想咨询以下几个问题:
- 这种情况下A对象的线程安全是否能得到保障?
synchronized作用于B的实例而非A对象(synchronized(this)等同于锁定B实例),这个理解对吗?- 是否需要使用
synchronized(a)代码块来提升线程安全性? - 实际中第一种写法仍不具备线程安全性,即便这是修改该公开对象的唯一方法,原因是什么?
相关代码示例:
// 写法1:同步方法 public class B { public synchronized void updateA(A a) { // 操作a的逻辑 } } // 写法2:同步B实例的代码块 public class B { public void updateA(A a) { synchronized (this) { // 操作a的逻辑 } } } // 写法3:同步A对象的代码块 public class B { public void updateA(A a) { synchronized (a) { // 操作a的逻辑 } } }
分析与解答
直接给结论:写法1和写法2都无法保障A对象的线程安全,只有写法3能有效保护对A对象的操作。下面逐个拆解细节:
关于synchronized锁定对象的理解
你的判断是对的:
- 写法1的
synchronized方法,本质就是锁定当前B类的实例,和写法2的synchronized(this)逻辑完全一致。 - 这两种写法锁的都是B的实例,而非传入的A对象。
写法1/2线程不安全的核心原因
哪怕updateA是修改A对象的唯一方法,只要出现以下场景,线程安全就会失效:
- 多个B实例操作同一个A对象:比如线程1用B1实例调用
updateA(a),线程2用B2实例调用updateA(a)。B1和B2是不同的对象,各自的锁互不干扰,两个线程会同时进入方法操作同一个A对象,必然出现并发问题。 - 外部直接操作A对象:因为A是公开可用的,哪怕你只通过B的方法修改A,只要别的线程能直接拿到A的引用并修改(比如直接调用
a.setXXX(...)),这些操作不受B实例锁的约束,同样会破坏线程安全。
写法3能保障线程安全的原因
写法3直接锁定A对象本身:
- 不管是通过哪个B实例操作A,只要操作A的代码都用
synchronized(a)包裹,就能保证同一时间只有一个线程能修改这个A对象。 - 如果其他地方也要操作A,只要同样遵循锁定A对象的规则,就能整体保障A的线程安全。
额外提醒
如果A对象本身是不可变的,那不需要任何同步;但如果是可变对象,所有修改和读取A的操作都必须在同一个锁(也就是A对象本身)的保护下,才能真正实现线程安全。
内容的提问来源于stack exchange,提问作者Mary
相关产品推荐
相关产品推荐

