[英]wait() does not free all current locks, how it can be done?
根据Java doc,当obj1.wait()
发生时,“线程释放此监视器的所有权并等待直到另一个线程通知......”
因此,obj1的锁定被释放,而当前线程正在等待。 但是所有其他锁呢? 有可能,代码片段锁定了两个对象:
synchronized(obj2){
f1();
synchronized(obj1){
f2();
obj1.wait();
}
}
Obj2将不会被释放,但线程不会运行,另一个线程将等待释放obj2徒劳...我不明白继续锁定obj2的原因。 但好吧,它就是这样。
但是我怎样才能更好地组织这种等待,如何在等待所有或至少几个当前锁定时解锁?
您可以使用比sychronized
语句更灵活的Lock和Condition 。
对于您的示例,您可以使用ReentrantLock
替换obj2
:
Lock lock2 = new ReentrantLock();
try {
// Blocks until the lock is acquired, just like a `synchronized` statement
lock2.lock();
f1();
synchronized (obj1) {
f2();
lock2.unlock();
obj1.wait();
lock2.lock();
}
}
// Use `finally` to make sure the lock is always released, even if an exception is thrown
finally {
// Exception might have been thrown before current thread could acquire lock again, cannot
// unlock then
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
}
但是,这将允许另一个线程在当前线程开始等待obj1
之前获取lock2
。 如果不希望这样,你可以用一个Lock
代替obj1
并等待obj2
。
但是所有其他锁呢?...我不明白继续锁定obj2的原因
Java编译器和运行时库都无法知道解锁obj2是否安全 。 锁定对象的全部原因是为了防止其他线程看到处于不一致状态的共享数据。 您编写synchronized (obj2) {...}
的唯一原因是,当obj2
被锁定时,您的程序将执行某些操作,除了正在执行此操作的其他线程之外,它应该被隐藏。
程序员有责任知道清理混乱的时间以及解锁时的安全性。 编译器无法为您执行此操作。
那么为什么,你可能会问, obj1.wait()
解锁obj1
? 那是因为,如果你按照它们的使用方式使用wait()
和notify()
,那么解锁必须是等待的原子。 在第一个线程解锁obj1
的时刻和进入等待状态的时刻之间,某些其他线程无法进入并传递obj1.notify()
。 如果可能,那么通知可能会丢失,程序将挂起。
您可以通过阅读Oracle的“Guarded Blocks”教程,了解wait()
和notify()
为何如何工作以及如何使用它们。
https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.