FixedThreadPool和ExecutorCompletionService的OutOfMemory错误

时间:2011-10-27 16:13:51

标签: java concurrency out-of-memory executorservice completion-service

我正在研究应该从db获取用户列表的内容,并从目录(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);
}
}
  

ERROR CheckGroupMembership:85 - java.lang.OutOfMemoryError:无法创建新的本机线程   java.util.concurrent.ExecutionException:java.lang.OutOfMemoryError:无法创建新的本机线程       at 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 个答案:

答案 0 :(得分:2)

我很难相信你没有在GetUsersDLTask(或者至少是它的服务对象)中创建一个线程。如果查看堆栈跟踪,则会从Future的get()方法抛出异常。设置此异常的唯一方法是在Executor调用Callabale.call()之后。 call()方法中出现的任何throwable都将在Future的内部exception字段中设置

例如:

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

否则,当您向线程池提交请求时,将发生此异常,而不是从将来获得此异常。

答案 1 :(得分:0)

Executors.newFixedThreadPool将接受许多任务的提交,但只会执行您允许的线程数。因此,如果您有一个包含2个线程的固定池,但是您提交了50个任务,那么其他48个任务将在执行程序内部排队,并在执行线程完成任务时运行。好像你需要限制你在代码中产生的线程数。

修改:查看http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int

答案 2 :(得分:0)

您是否验证了固定池中创建的线程数。也许可用的处理器数量太大了。