【发布时间】:2016-03-18 11:16:05
【问题描述】:
我在代码中添加了 cmets 来解释发生死锁的位置。
基本上,有两个线程。每个线程获取一个Manager对象的锁,然后去获取静态资源的锁,这是应用程序中所有Manager对象的映射。两个线程都调用映射上的get()。
Manager 类已覆盖 equals() 方法。 equals() 进一步调用了Manager 类的一些同步方法。因此,映射上的get() 将需要对映射中的每个对象一个一个的对象级锁定,直到键匹配,因为 equals 被覆盖。
我只能更改子类中的代码(Sub1 和Sub2)并避免死锁,因为我无法访问其他类。
编辑:我无权访问 syncMap。 “同步”块中的代码在我调用其 API 的第三方代码中执行。
我可以通过在Manager 上获得锁定finally 来避免这种情况,而不是在尝试阻止之前?!
public class Parent{
protected Manager manager;
}
public class Global{
private static final Map syncMap = Collections.synchronizedMap(new HashMap());
//syncMap contains all the objects of Manager in the application
}
class Manager{
public boolean equals(Object o){
Manager obj = (Manager)o;
return obj.getURL().equals(getURL());
}
public final synchronized String getURL(){
return msettings.getDBURL(); //msettings is a global variable
}
}
//Thread-1 is executing someMethod() of this class
class Sub1 extends Parent{
Global global;
//consider manager and Global object are not null
public void someMethod()
{
synchronized(manager){// Thread-1 succesfully takes object level lock on a manager object, say Manager01
try{
global.syncMap.get(manager);
// Thread-1 Succesfully takes class level lock on syncMap
// get() calls equals() for each object in syncMap.
//equals() need object lock on each Manager Object in map as it further calls synchronized getURL()
// But on one manager Object(Manager02) Thread-2 has already acquired lock and is waiting for lock on syncMap which this thread-1 holds
}
finally{
manager.releaseConnection();
}
}
}
}
//Thread-2 is executing otherMethod() of this class
class Sub2 extends Parent{
public void otherMethod()
{
synchronized(manager){// this takes a lock on manager(Manager02)
try{
global.syncMap.get(manager);
// this is blocked as syncMap is aquired by thread-1
}
finally{
manager.releaseConnection();
}
}
}
}
【问题讨论】:
-
您认为为什么会出现死锁?这段代码应用了带同步(管理器)的有序内在锁,所以我没有看到死锁......
-
我的雇主组织面临僵局。线程转储说这只发生在这里。线程 1 在 syncMap 上具有类级别锁定,并且正在等待 SyncMap 中可用的 Manager 类实例的锁定。另一个线程已锁定 Manager 对象,正在等待锁定 SyncMap。 Manager 可以有多个实例,所有实例都在 SyncMap 中进行记录。
-
完全没有必要强制一个设计,其中
equals正在做同步的东西,摆脱它。充其量在某些客户端代码中评估equals会告诉您,在equals 调用期间 的状态是什么,并且在调用后不提供任何状态的承诺。而是实现原子操作 (trySomeOperation),告诉调用者所需的条件是否符合预期并且操作是否已执行。 -
Sub1 和 Sub2 对象是如何实例化的?他们是否拥有相同的管理器实例?你能描述一下你是如何启动你的线程的吗?
-
Sub1 和 sub2 具有不同的管理器对象。管理器对象由一些我们无权访问的 API 调用返回。 API 通过 Map 跟踪所有管理器对象。为简单起见,我没有显示 API 调用。我通过 java 反编译器查看了 API 代码,并将该代码添加到我的代码的同步块中,以便在此处发布。
标签: java multithreading deadlock java-threads