拿这个代码:
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)
}
}
}
是否可以通过传递其锁定var来重写“myMethod”以使用HelperClass,以便一切仍然是线程安全的?即,
public void myMethod() {
_helperObject.helperMethod(_lock, _mutableObject);
}
我不确定这一点,因为Java将通过值传递lockVar,并且每个线程将获得一个单独的lockVar副本(即使每个副本指向堆上的同一个对象).我想这个问题归结为’synchronized’关键字是如何工作的 – 它是锁定变量还是变量引用的堆上的值?
解决方法:
同步是在对象上完成的,而不是变量.
变量/成员[有时]包含对象,它是[variable] x中包含的结果对象,实际上在synchronized(x)中同步.
变量的线程可见性还存在一些其他问题(例如,可能从变量中读取“陈旧”对象),但这不适用于:没有_lock的重新赋值和初始的可见性(“final” “)保证分配.因此,在这种情况下,方法参数将始终包含用于同步的正确(相同)对象.
但是,如果使用的锁定对象(可能是_lock不是最终的)发生了变化,则需要重新评估适当的值/线程可见性,但不会与任何跨线程访问不同.
快乐的编码.