您可以安全地同步 Java 方法参数吗?
Posted
技术标签:
【中文标题】您可以安全地同步 Java 方法参数吗?【英文标题】:Can you safely synchronize on a Java method parameter? 【发布时间】:2011-09-06 18:29:31 【问题描述】:获取此代码:
public class MyClass
private final Object _lock = new Object();
private final MyMutableClass _mutableObject = new MyMutableClass()
public void myMethod()
synchronized(_lock) // we are synchronizing on instance variable _lock
// do something with mutableVar
//(i.e. call a "set" method on _mutableObject)
现在,想象一下将 myMethod() 中的代码委托给您传递锁的某个辅助类
public class HelperClass
public helperMethod(Object lockVar, MyMutableClass mutableVar)
synchronized(lockVar) // we are now synchronizing on a method param,
// each thread has own copy
// do something with mutableVar
// (i.e. call a "set" method on mutableVar)
可以重写“myMethod”以通过传递它的锁变量来使用 HelperClass,这样一切仍然是线程安全的吗?即,
public void myMethod()
_helperObject.helperMethod(_lock, _mutableObject);
对此我不确定,因为 Java 会按值传递 lockVar,并且每个线程都会获得一个单独的 lockVar 副本(即使每个副本都指向堆上的同一个对象)。我想问题归结为“同步”关键字的工作原理——它是锁定变量还是变量引用的堆上的值?
【问题讨论】:
【参考方案1】:同步是在对象上完成的,而不是变量。
变量/成员 [有时] 包含 objects,它是包含在 [variable] x
中的结果 object 实际上在 synchronized(x)
中同步。
变量的线程可见性还有一些其他问题(例如,可能从变量中读取“陈旧”对象),但这不适用于这里:没有重新分配 _lock
和可见性保证初始(“最终”)分配。因此可以保证,在这种情况下,方法参数将始终包含用于同步的正确(相同)对象。
但是,如果使用的锁定对象(可能_lock
不是最终的)发生更改,则需要重新评估适当的值/线程可见性,但与任何跨线程访问没有区别。
编码愉快。
【讨论】:
实际上,我的例子并不正确。我并不是要将 _mutableObject 标记为最终的。我不认为这种锁定会起作用 IF 父对象中的 _mutableObject 是非最终的。如果将该值作为变量传递给辅助方法,然后将 _mutableObject 更改为指向父类中的其他内容,则当辅助方法运行时,它不再保留 _mutableObject 的正确引用。锁仍将锁定,但您将“保护” _mutableObject 的陈旧值。这确实是我的问题应该指出的。 我会接受您的回答,假设这仅在父类中 _mutableObject 为“final”时才有效。无论您使用我的示例的哪个版本,_lock 对象始终需要声明为 final。事实上,我不应该创建我的示例来包含“可变”对象。我应该刚刚描述了我想保护一个非最终变量,称之为“私有对象_object”。我想要锁来保护这个值的变化。如果将示例更改为该示例,我认为您不能将锁定传递给辅助方法,因为辅助方法会获取陈旧的 _object 引用。 @android Dev 用于锁定的对象 object 对于所需的每个互斥同步应该是稳定且唯一的。受同步保护的变量(或对象)可以更改(同步上下文将确保内存屏障和发生前的保证,只要所有此类同步都在同一个锁对象上操作)。交换用于锁定的对象通常是一个坏主意(锁定 object 可以改变,这不会影响它与synchronized
的使用——重要的是 相同的对象 用于同步。)
我没有交换用于锁的对象。我正在用锁交换我正在保护的对象。我理解您所说的关于锁 object (非变量)上发生的同步的内容。但是,如果我试图通过使用锁来保护实例变量,我认为我不能编写一个辅助方法并将该变量传入(使用锁,我可以传入),因为一旦我通过作为参数的变量,它可以被另一个线程更改。在传递给辅助方法之前,我需要在锁上同步。这就是我需要解决的方法。以上是关于您可以安全地同步 Java 方法参数吗?的主要内容,如果未能解决你的问题,请参考以下文章
我可以将数组作为参数传递给 Java 中具有可变参数的方法吗?
如何安全地为 bigquery 节点插入转义用户输入?可以在 bigquery.insert 节点库上使用参数化查询吗?