Java 理解锁类与同步
在Java并发实践中,我使用了避免死锁的技术。当我们需要获取多个锁以确保一致性时,他建议获取useJava 理解锁类与同步,java,multithreading,locking,Java,Multithreading,Locking,在Java并发实践中,我使用了避免死锁的技术。当我们需要获取多个锁以确保一致性时,他建议获取usetryLock()。详情如下: public void m(MyObject o1, MyObject o2){ synchronized(o1){ synchornized(o2){ //... } } } 相反,我们最好使用以下方法: public void m(MyObject o1, MyObject o2){
tryLock()
。详情如下:
public void m(MyObject o1, MyObject o2){
synchronized(o1){
synchornized(o2){
//...
}
}
}
相反,我们最好使用以下方法:
public void m(MyObject o1, MyObject o2){
while(true){
if(o1.lock.tryLock(){
try{
if(o2.lock.tryLock(){
try{
//...
} finally {
o2.lock.unlock();
}
}
} finally {
o2.lock.unlock()
}
}
}
}
现在他说:
此技术仅在同时获取两个锁时有效;如果
由于方法调用的嵌套,您无法获得多个锁
只需重新打开外部锁,即使你知道你拿着它
这不太明显。在方法中调用方法时,为什么不能使用此选项?你能举个例子吗?我刚刚翻阅了这本书,发现引用的语句是在定时锁的上下文中做出的(使用
tryLock(long time,TimeUnit)
),但我认为它也适用于你的tryLock()
示例
理论上,您仍然可以在嵌套方法调用中使用此技术,但它很快就会变得非常笨拙。让我们考虑一个简单的例子,您尝试在方法<代码> FoO(锁锁)中获得一些锁,如果成功,后面的两个堆栈帧将尝试在方法<代码>栏(锁锁)< /C> >中获得另一个锁。
- 如果您的两个方法都使用
,直到它们最终设法获得锁,那么如果一个线程在while(true)
中获得了foo()
,另一个线程在a
中获得了foo()
,并且现在这两个线程都在B
中无休止地旋转,则很容易陷入死锁,试图获得对方的锁bar()
- 如果在锁获取失败时仅在
方法中循环并从foo()
返回,则可以避免死锁,但现在:bar()
和foo()
紧密耦合bar()
- 根据调用
的确切时间,获取第一个锁和获取第二个锁之间的漏洞窗口可能非常大bar()
- 您需要从
foo()中的循环开始重新计算整个分支
- 目标代码路径变得很难遵循,也很容易被破坏
- 如果使用定时锁,您仍然会遇到上述一些问题,您需要处理
,并且需要决定如何循环。InterruptedException
- 一般技术已经倾向于生成大量的
s,这并不太好IllegalMonitorStateException
- 一般技术已经倾向于生成大量的
如果您定期获取相同的锁子集并使用相同的子集资源,则可能需要考虑锁粗化(将两个锁合并为一个)或重新定义资源保护策略,以便不需要在单个工作流中获得多个级别的锁。
另外,经过几次尝试,我得到了
tryLock()
和timedtryLock(长时间,时间单位)
方法来使用上述两种方法,两种锁方案。不太好看,我可以很容易地看出,在受保护部分进行简单的更改会破坏整个方案,或者使其变得过于复杂。请查看@Boris the Spider的评论: