【发布时间】:2016-03-04 16:21:27
【问题描述】:
我正在查看一些在 Java 6 及更高版本中导致问题(死锁)的代码,但在 Java 1.5 中却没有。
BMP 豆:
private MyClass m_c;
public String ejbCreate(String id) throws CreateException, MyException
{
try
{
m_c = Singleton.getInstance().getObj(id);
}
catch (MyException e)
{
synchronized (Singleton.getInstance())
{
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
}
else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
单例:
private Map objCache = new HashMap();
private static Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
public void addObj(String id, MyClass o)
{
if (this.objCache.containsKey(id)) {
this.objCache.remove(id);
}
this.objCache.put(id, o);
}
public MyClass getObj(String id) throws Exception
{
MyClass o = null;
o = (MyClass)this.objCache.get(id);
if (o == null) {
throw new MyException("Obj " +id+ " not found in cache");
}
return o;
}
public boolean hasObj(String id)
{
return this.objCache.containsKey(id);
}
到目前为止的经验证据表明,在整个 try/catch 中进行同步可以解决使用 Java 6 时的死锁。
显然可以有一个或多个线程调用
Singleton.getInstance().getObj(id)
没有获得锁,而另一个线程拥有锁并正在执行同步块中的代码,但即使在考虑了 JSR-133 中详述的内存同步之后,在这种情况下看起来也不应该有任何问题。
我知道我没有解释问题是什么,只是说这是一个僵局,只画一小部分并不理想,但要画整个画面会占用很大的画布。
我查看了 Java 6 版本的注释,唯一听起来相关的领域是无竞争同步,但我不知道这在这种情况下是否重要。
感谢您的帮助。
【问题讨论】:
-
要获得死锁,您需要尝试在不同的线程中同时获得两个或更多锁。单独一把锁不会死锁。您能否展示使用其他锁以及如何以不同的顺序获得这些锁?
-
注意:如果您以不安全的方式更新地图,可能会进入无限循环。这一直存在。我会考虑让整个代码线程安全,如果您需要并发访问,请使用 ConcurrentMap(在 Java 5.0 中添加)
-
顺便说一句,如果你有一个真正的死锁,并且这一切都来自使用内置的
synchronized关键字,那么线程转储实际上会检测到死锁并告诉你它。如果你没有看到,这是彼得理论的有力证据。 -
这是有症状的。您正在一个接一个地执行几个不必要的哈希查找,但试图通过双重检查锁定反模式来提高性能。看
addObj;它确实if(map.containsKey(key)) { map.remove(key); } map.put(key, …);,执行三个哈希查找来完成单个map.put(key, …);所做的事情。或者,当密钥不存在时,ejbCreate会发生什么,首先是未同步的get,然后是同步的hasObj(containsKey),然后是addObj(另一个containsKey,然后是 @ 987654334@) 总共进行了四次查找... -
这段代码肯定是由于双重检查锁定而被破坏的,但是,涉及两个锁的死锁不会发生在只有一个锁的一段代码中,但是代码显然不是你真正的代码,因为它甚至没有编译,由于未处理/未声明的异常和缺少返回语句等。
标签: java multithreading jvm synchronization jdk1.6