我想知道是否有一种简单的方法可以使synchronized
锁定响应更改的引用。我的代码看起来像这样:
private void fus(){
synchronized(someRef){
someRef.roh();
}
}
...
private void dah(){
someRef = someOtherRef;
}
我想要发生的是:
fus
,并在调用someref
时获取roh()
上的锁定。假设roh
永远不会终止。fus
,开始等待someRef`空闲,并保持原状(暂时)。dah
,并修改someRef
。someRef
不再引用对象线程A已锁定。实际发生的是:
fus
,并在调用someref
时获取roh()
上的锁定。假设roh
永远不会终止。fus
,找到锁,并等待它被释放(永远)。dah
,并修改someRef
。someref
,它正在查看A所持的锁定。有没有办法设置它,以便线程B重新检查锁定以更改引用,或者"反弹"进入其他代码? (像sychronizedOrElse?)
答案 0 :(得分:3)
肯定有办法,但不是synchronized
。推理:在第二个线程进入fus()
的时间点,第一个线程保存someRef
引用的对象的内部锁。重要提示:第二个线程仍会看到someRef
引用此对象,并将尝试获取此锁。稍后,当第3个线程更改引用someRef
时,它必须以某种方式通知第二个线程关于此事件。 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
。
答案 1 :(得分:2)
实际发生的是......线程B继续等待,因为它不再看
someref
,它正在查看A持有的锁。
那是对的。您无法编写代码以在变量上进行同步。您只能编写代码以在某些对象上进行同步。
线程B通过查看变量someref
找到要同步的对象,但它只查看该变量一次才能找到该对象。 对象是它锁定的内容,并且在线程A释放对该对象的锁定之前,线程B将被卡住。
答案 2 :(得分:1)
我想在@ Turing85
和@ james large
的优秀答案之外添加更多信息。
我同意Thread B
继续等待。
通过使用更好的无锁API,最好避免synchronization
这类程序。
Atomic
个变量具有最小化同步的功能,有助于避免内存一致性错误。
根据您发布的代码,AtomicReference似乎是您问题的正确解决方案。
查看Atomic包上的文档页面。
一个小型工具包,支持对单个变量进行无锁线程安全编程。本质上,此包中的类将volatile值,字段和数组元素的概念扩展为也提供表单的原子条件更新操作的那些:
boolean compareAndSet(expectedValue, updateValue);
SE中与本主题相关的另一篇不错的帖子。
When to use AtomicReference in Java?
示例代码:
String initialReference = "value 1";
AtomicReference<String> someRef =
new AtomicReference<String>(initialReference);
String newReference = "value 2";
boolean exchanged = someRef.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);
有关更好的理解,请参阅此jenkov教程。