我想知道是否有一种简单的方法可以创建一个同步
锁来响应不断变化的引用。我的代码看起来像这样:
private void fus(){
synchronized(someRef){
someRef.roh();
}
}
...
private void dah(){
someRef = someOtherRef;
}
我希望发生的是:
- 线程 A 进入
fus
,并在调用roh()
时获取someref
上的锁。假设roh
永远不会终止。 - 线程 B 进入
fus
,开始等待 someRef` 空闲,并停留在那里(暂时)。 - 线程C进入
dah
,修改someRef
。 - 现在允许线程 B 进入同步块(synchronized block),因为
someRef
不再引用线程 A 锁定的对象。
实际发生的是:
- 线程 A 进入
fus
,并在调用roh()
时获取someref
上的锁。假设roh
永远不会终止。 - 线程 B 进入
fus
,找到锁,并等待它被释放(永远)。 - 线程C进入
dah
,修改someRef
。 - 线程 B 继续等待,因为它不再查看
someref
,而是查看 A 持有的锁。
有没有办法设置它,以便线程 B 重新检查锁以更改引用,或者将“弹回”到其他代码? (类似 sychronizedOrElse 的东西?)
最佳答案
肯定有办法,但不是synchronized
。推理:在第 2 个线程进入 fus()
的时间点,第一个线程持有 someRef
引用的对象的内部锁。重要提示:第二个线程仍然会看到 someRef
引用这个对象,并会尝试获取这个锁。稍后,当第 3 个线程更改引用 someRef
时,它必须以某种方式将此事件通知第 2 个线程。这对于 synchronized
是不可能的。
据我所知,没有像synchronized
这样的内置语言特性来处理这种同步。
一种稍微不同的方法是管理 Lock
在你的类中或者给 someRef
一个 Lock
类型的属性。除了使用 lock()
,您还可以使用 tryLock()
或 tryLock(long timeout, TimeUnit unit)
。这是我将如何实现它的方案(假设 someRef
有一个 Lock
属性):
volatile SomeRef someRef = ... // important: make this volatile to deny caching
...
private void fus(){
while (true) {
SomeRef someRef = this.someRef;
Lock lock = someRef.lock;
boolean unlockNecessary = false;
try {
if (lock.tryLock(10, TimeUnit.MILLISECONDS)) { // I have chonse this arbritrarily
unlockNecessary = true;
someRef.roh();
return; // Job is done -> return. Remember: finally will still be executed.
// Alternatively, break; could be used to exit the loop.
}
} catch (InterruptException e) {
e.printStackTrace();
} finally {
if (unlockNecessary) {
lock.unlock();
}
}
}
}
...
private void dah(){
someRef = someOtherRef;
}
现在,当 someRef
改变时,第二个线程将在其下一个周期看到 someRef
的新值,因此将尝试在新的 上同步Lock
并成功,如果没有其他线程获得 Lock
。
关于java - 重新检查 "synchronized"锁的可变引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37333529/