java多线程不使用所有核心

时间:2012-08-18 19:00:01

标签: java multithreading nlp executorservice stanford-nlp

我有一个多线程程序,似乎并没有真正利用我机器中的所有内核。这是代码,任何输入将受到高度赞赏。

  

主类

public class MainClass{
 public static void main(String [] args){
  Work work=new Work();
  work.doIt();
 }
}

第二个类创建任务并将它们交给ExecutorService,这里是伪代码

public class Work{
 public void doIt() throws InterrputedException, Exception{
  map=get some data and put it in the map;
  ArrayList<Future<Integer>> list=new ArrayList<Future<Integer>>();
  ArrayList<WorkCallable>jobs=new ArrayList<WorkCallable>();
  for each entry in the map;
    jobs.add(new WorkCallable(entry);
  int numCores=Runtime.getRuntime().availableProcessors();
  ExecutorService executor=Executors.newFixedThreadPool(numCores);
  int size=jobs.size();
  for(int i=0;i<size;i++){
    Callable<Integer> worker=jobs.get(i);
    Future<Integer> submit=executor.submit(worker);
    list.add(submit);
  }
  executor.shutdown();
  while(!executor.isTerminated()) {}
  do something with the returned data;
}
}

Callable类

public class WorkCallable implements Callable<Integer>{
 @Override
 public Integer call() throws Exception{
   Properties props=new Properties();
   props.put("annotators", "tokenize, ssplit, pos");
   StanfordCoreNLP pipeline=new StanfordCoreNLP(props);
   for(String id:entry.keySet()){
   Annotation document=new Annotation(entry.get(id));
   pipeline.annotate(document);

   process the data;
   return an integer value;
 }
}

问题在于,当我检查有多少线程正在运行时,我发现只有很少的线程,而且执行器似乎没有利用理想的内核!

我希望描述清楚。

更新

  • 使用的库是StanfordCoreNLP包,用于处理传递给Callable对象的文本作为documentID及其内容的Map。处理数据不是问题,因为我没有包含StanfordCoreNLP库就可以正常工作。换句话说,文档的浅层处理工作正常并利用所有核心。但是,当我包含这个包时,它不会。

2 个答案:

答案 0 :(得分:1)

如果您使用的是Windows,则JVM将委派调度NT内核的线程。 POSIX类型的操作系统直接将操作系统线程映射到JVM并进行协同调度。

但是,无论发生什么,您都无法确保在核心/处理器之间均匀分配线程。当你启动第4个线程时,操作系统上的其他东西可以在核心4上运行,因此它可能被安排到另一个核心。或者调度程序可以决定将它们堆叠在同一个核心上。

答案 1 :(得分:0)

此时您提供的信息我怀疑线程之间存在争用,因此有些线程被阻塞/等待。要验证这一点,您可以使用JVisual VM并进行线程转储(Jconsole也是一个选项)。 JVisual VM是用于监视Java应用程序的实用程序,它随JDK一起提供。如果您之前没有使用它,那将是您花时间学习它的好方法,因为它非常有用且易于使用。

See Here for JVisualVM

  1. 使用JVisual VM Take Thread dump连接到您的程序。
  2. 它将为您提供程序中的线程状态 时间的例子,如果存在争用和/或阻塞,那将很容易     使用线程转储。
  3. 如果您无法弄清楚是什么,请随意将其粘贴在此处 发生在线程转储中,虽然有多少资源 你了解网上的线程转储
  4. 另一方面,正如@Marko指出的那样,你可以更有效地处理执行程序关闭,我会说ExecutorCompletionService符合你的要求,使代码更优雅,更容易阅读。 Check here for ExecutorCompletionService一旦你弄清楚空闲核心,你就可以重构使用ECS。