4

我正在开发应用程序,应该从 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);
}
}

错误 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);
}

}
4

3 回答 3

3

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

例如:

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

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

于 2011-10-27T17:36:07.770 回答
1

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

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

于 2011-10-27T16:18:38.360 回答
0

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

于 2011-10-27T17:25:05.187 回答