关于J2EE中死锁问题的研究
http://tech.ddvip.com 2006年11月21日 社区交流
本文详细介绍关于J2EE中死锁问题的研究
当处理此情形的实例时,将有一个等待数据库响应的Java线程和一个等待获取Java虚拟机锁的线程。每个线程将与一个数据库连接相关联,其中一个连接阻塞另一个连接。修复方法是占有Java虚拟机锁时避免执行数据库操作,可以重写leCache的get()方法,如下所示:
public Object get(String key) {
synchronized(this) {
if (cache.containsKey(key)) {
return cache.get(key);
}
}
Object value = queryForValue(key);
synchronized(this) {
cache.put(key, value);
}
return value;
}
既然现在我们知道了会发生此死锁情况,就可以使用Thread.holdsLock()向queryForValue方法添加检查以尝试避免死锁情况:
private Object queryForValue(String key) {
assert(!Thread.holdsLock(this));
return executeQuery(...);
}
上例中的Thread.holdsLock()很有用,但是只有在我们知道需要留心哪个锁时它才会发挥作用。如果有一个类似的方法可以确定当前线程占有哪个Java虚拟机锁,那么会很有用。任何执行任何种类的RPC调用、数据库访问等的代码片段都可以抛出异常或记录警告,指示在占有Java虚拟机锁时执行这些操作会有危险。
注意:虽然我们修复了上例中的死锁问题,但它仍有缺陷,因为在提交updateData的事务之前清空了缓存。如果在调用clearCache后、提交updateData事务前出现缓存缺失,则该缓存将加载旧数据,因为新数据尚未可见。这里的修复方法是仅在提交更改后清空缓存。注意,这只在MVCC数据库中发生。在基于锁的数据库中,挂起的update将阻塞缓存的读操作,所以在提交update的事务后缓存才能读取正确值。
来源:bea 作者:Michael Nonemacher 责编:豆豆技术应用