Ошибка OutOfMemory с FixedThreadPool и ExecutorCompletionService - PullRequest
3 голосов
/ 27 октября 2011

Я работаю над приложением, которое должно получить список пользователей из базы данных и обновить данные из каталога (ldap или AD). Я, что делать эту процедуру на многоядерной машине, поэтому я создал это приложение (код ниже). Я использую CompletionService и получаю результаты в объекте Future.

Через некоторое время я получаю сообщение об ошибке «Недостаточно создать новый собственный поток». В диспетчере задач я вижу, что приложение создает огромное количество потоков, но я попросил создать фиксированный пул потоков с размером равным количеству моих процессоров.

Что не так с моим кодом?

class CheckGroupMembership {
public static void main(String[] args) throws Exception {

    final ExecutorService executor = Executors.newFixedThreadPool(**Runtime.getRuntime().availableProcessors()**);

    CompletionService<LdapPerson> completionService =
        new ExecutorCompletionService(executor)<LdapPerson>(executor);

    final int limit = 2000;

    DocumentService service1 = new DocumentService();
    List<String> userNamesList = service1.getUsersListFromDB(limit);

    List<LdapPerson> ldapPersonList = new ArrayList() <LdapPerson> (userNamesList.size());
    LdapPerson person;

    for (String userName : userNamesList) {
        completionService.submit(new GetUsersDLTask(userName));
    }

    try {
        for (int i = 0, n = userNamesList.size(); i < n; i++) {
            Future<LdapPerson> f = completionService.take();
            person = f.get();
            ldapPersonList.add(person);
        }
    } catch (InterruptedException e) {

        System.out.println("InterruptedException error:" + e.getMessage());
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    System.exit(0);
}
}

ОШИБКА CheckGroupMembership: 85 - java.lang.OutOfMemoryError: невозможно создать новый собственный поток java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: невозможно создать новый собственный поток в java.util.concurrent.FutureTask $ Sync.innerGet (FutureTask.java:222) в java.util.concurrent.FutureTask.get (FutureTask.java:83

Задача GetuserDLs

public class GetUsersDLTask implements Callable<LdapPerson> {
private String userName;

public GetUsersDLTask(String u) {
    this.userName = u;
}

@Override
public LdapPerson call() throws Exception {
    LdapService service = new LdapService();
    return service.getUsersDLs(userName);
}

}

Ответы [ 3 ]

2 голосов
/ 27 октября 2011

Мне трудно поверить, что вы не создаете поток в GetUsersDLTask (или, по крайней мере, это служебный объект).Если вы посмотрите на свою трассировку стека, исключение выдается из метода get() будущего.Единственный способ установить это исключение get - это после того, как Executor вызовет Callabale.call().Любой бросок, который происходит в методе call(), будет установлен во внутреннем поле exception Future

Например:

Thread Pool: 
    Thread-1
      invoke call()
        call() 
          Create Thread
            throw OutOfMemoryError 
         propogate error to Thread pool
      set exception

В противном случае это исключение будет происходить при отправкепопросить пул потоков, а не когда вы получите из будущего.

0 голосов
/ 27 октября 2011

Проверено ли количество потоков, созданных в фиксированном пуле.Возможно, число доступных процессоров слишком велико.

0 голосов
/ 27 октября 2011

Executors.newFixedThreadPool примет представление многих задач, но выполнит только количество потоков, которые вы разрешите. Таким образом, если у вас есть фиксированный пул из 2 потоков, но вы отправляете 50 задач, то 48 других задач помещаются в очередь внутри исполнителя и выполняются по мере выполнения задач выполняющимися потоками. Похоже, вам нужно ограничить количество потоков, которые вы порождаете в своем коде.

Редактировать: проверить http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)

...