S2Hibernateでデッドロック?

S2Hibernateを使用して開発をしているが、ぶんまわしテスト中にTomcatがハングしてしまった。
どうも、以下のクラスでデッドロックが起きているようだ。

ConnectionPoolImpl#checkOut()では、

while (getActivePoolSize() + getTxActivePoolSize()
	>= getMaxPoolSize()) {
	try {
		wait();
	} catch (InterruptedException ignore) {
	}
}

となっている。プールの上限になったら空くまで待っているようだ。
ところで、このメソッドは、S2SessionFactoryImpl#getConnection()から呼ばれている。
もっと遡ると、S2SessionFactoryImpl#bindSession()、S2SessionFactoryImpl#getSession()から呼ばれている。
ここで、S2SessionFactoryImpl#bindSession()は、synchronizedメソッドであることに気がついた。
S2SessionFactoryImplのシングルトンをロックしたまま、ConnectionPoolImplでwait()してしまっているようだ。

S2SessionFactoryImpl#closeSession()もsynchronizedメソッドのため、コネクションをプールに戻そうにもブロックされてしまっているようだ。
なにぶん、Seasarを使うのは初めてなので、設定が間違っている可能性も高い。とりあえず、S2SessionFactoryImplのソースをコピーして別のクラスを作成してしのぐことにした。


自作S2SessionFactoryImplでは、以下のようにした。

private S2Session bindSession(Transaction tx) {
	S2Session session = null;
	session = (S2Session) txSessions_.get(tx);
	if (session != null && session.isOpen()) {
		return session;
	}
	session = createSession();
	synchronized (this) {
		txSessions_.put(tx, session);
	}
	TransactionUtil.registerSynchronization(tx, this);
	return session;
}

private void closeSession() {
	Transaction tx = getTransaction();
	if (tx == null) {
		return;
	}
	S2Session session = null;
	synchronized (this) {
		session = (S2Session) txSessions_.remove(tx);
	}
	if (session != null && session.isOpen()) {
		try {
			if (!session.isReadOnly()) {
				session.flush();
			}
		} finally {
			Connection con = session.close();
			ConnectionUtil.close(con);
		}
	}
}

テストしたところ、ハングしなくなった。
正しいかどうかはともかくとして、とりあえずこれでいいか。