我试图了解 Struts2 ScopeInterceptor 类(/org/apache/struts2/interceptor/ScopeInterceptor.java)内部是否存在线程安全问题,这是有问题的代码:
private static Map locks = new IdentityHashMap();
static final void lock(Object o, ActionInvocation invocation) throws Exception {
synchronized (o) {
int count = 3;
Object previous = null;
while ((previous = locks.get(o)) != null) {
if (previous == invocation) {
return;
}
if (count-- <= 0) {
locks.remove(o);
o.notify();
throw new StrutsException("Deadlock in session lock");
}
o.wait(10000);
}
;
locks.put(o, invocation);
}
}
static final void unlock(Object o) {
synchronized (o) {
locks.remove(o);
o.notify();
}
}
我有一个 Websphere 应用程序显示 45 个停滞的线程,CPU 使用率很高。33 个线程在“解锁”方法内的“locks.remove(o)”处停止。其他 12 个线程在 "lock" 方法内的 "locks.get(o)" 内停止。
在我看来,IdentityHashMap 的使用是线程不安全的。可以简单地用 Collections.synchronizedMap() 包装 IdentityHashMap 解决这个问题吗?:
private static Map locks = Collections.synchronizedMap(new IdentityHashMap());
static final void lock(Object o, ActionInvocation invocation) throws Exception {
synchronized (o) {
int count = 3;
Object previous = null;
while ((previous = locks.get(o)) != null) {
if (previous == invocation) {
return;
}
if (count-- <= 0) {
locks.remove(o);
o.notify();
throw new StrutsException("Deadlock in session lock");
}
o.wait(10000);
}
;
locks.put(o, invocation);
}
}
static final void unlock(Object o) {
synchronized (o) {
locks.remove(o);
o.notify();
}
}
在我看来,作者试图通过使用同步代码块来“修复”IdentityHashMap 的同步问题,但是如果对象“o”是特定于线程的对象,这并不能防止多线程。而且,由于 lock 和 unlock 中的代码块是分开的,因此 IdentityHashMap 将(并且确实!)被多个线程同时调用(根据我们的 Java 核心证据)。
Collections.synchronizedMap() 包装器是正确的修复,还是我遗漏了什么?