Почему DirContext.close ()не возвращает соединение LDAP с пулом?

При использовании пула подключений LDAP я заметил, что вызов close()в контексте не возвращает его в пул, несмотря на то, что в документации говоритсяиначе . Таким образом, когда я пытаюсь получить элемент из пула, когда он уже имеет максимальный размер, он зависает.

Мне удалось сузить его до минимального случая. Несмотря на то, что я полагаю, что вызываю close()для всех соответствующих объектов детерминистически, кажется, что он полагается на сборку мусора, чтобы фактически вернуть объекты в пул, что неожиданно. Почему это происходит? Есть ли какой-то другой объект, который я должен закрыть?

Во фрагменте кода ниже:

  • Я искусственно установил максимальный размер пула равным 1, чтобы подчеркнуть проблему.
  • Я получаю DirContextиз пула (строка (2 )), пытаюсь вернуть его в пул (строка (4 )), затем получаю еще один из пула (строка (6 )), которая должна возвращать тот же возвращаемый объект.
  • вместо этого вторая строка запроса ((6 ))зависает на каком-то внутреннем вызове Object.wait(). Я предполагаю, что он ждет, пока объект из пула станет доступным.
  • если отключить пул, закомментировав (1 ), то не зависает (, но я хочу пул! ).
  • если я закомментирую (3)-звонок наSearchResults.next()-это работает нормально.
  • если я раскомментирую строку (5 )для принудительной сборки мусора между вызовом «возврат в пул» и запросом нового объекта в пул, он не зависает.

Поскольку закомментирование строки (3 )устраняет проблему, возможно, я неправильно закрываю возвращаемое значение, и это держит соединение в пуле открытым. Однако,метод results.next()возвращаетSearchResultв этом случае, у которого нет метода closeи в его документации нет руководства о том, как его закрыть.

Тестовый случай:

@Test
public void testHangs() throws NamingException {

    System.setProperty("com.sun.jndi.ldap.connect.pool.debug", "fine");
    System.setProperty("com.sun.jndi.ldap.connect.pool.maxsize", "1");

    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.SECURITY_PRINCIPAL, user);
    env.put(Context.SECURITY_CREDENTIALS, passwd);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.PROVIDER_URL, ldapUrl);

    // use a connection pool
    env.put("com.sun.jndi.ldap.connect.pool", "true"); // -----------------  (1)

    // get a context from the pool.
    DirContext context = new InitialDirContext(env); // -------------------- (2)
    NamingEnumeration results = context.search("", query, getSC());
    // obviously the next two lines would normally be in a 
    // while(results.hasMore()) {... = results.next(); } loop.
    assertTrue(results.hasMore()); // this is only a problem when there are some results.
    results.next(); // ----------------------------------------------------- (3)

    // ensure the context is returned to the pool.
    results.close();
    context.close(); // ---------------------------------------------------- (4)

    //System.gc(); // ------------------------------------------------------ (5)

    new InitialDirContext(env);  // hangs here! ---------------------------- (6)
}

С кодом как есть моя консоль показывает:

Create com.sun.jndi.ldap.LdapClient@1a7bf11[ldapad:389]
Use com.sun.jndi.ldap.LdapClient@1a7bf11

В то время как если я форсирую сборщик мусора, я дополнительно вижу:

Release com.sun.jndi.ldap.LdapClient@93dee9 <-- on GC
Use com.sun.jndi.ldap.LdapClient@93dee9     <-- on new InitialDirContext

8
задан bacar 14 August 2012 в 15:09
поделиться