【问题标题】:MultiThread Java Only Utilize One Thread多线程 Java 只使用一个线程
【发布时间】:2013-09-08 10:05:57
【问题描述】:

我正在做这个项目,我想在我的代码中使用多线程。所以我开发了这段小代码并对其进行了测试,但结果发现它只使用了我计算机中的一个线程。谁能告诉我它有什么问题以及如何改进它?

public static int choiceCount(List<Character> charlist) throws InterruptedException, ExecutionException {

    int coreCount = 8;
    ExecutorService e1 = Executors.newFixedThreadPool(coreCount);
    Integer total = 0;
    for (int i = 0; i < coreCount; i++) {
        Future<Integer> result = e1.submit(new Count(coreCount, i, charlist));
        total += result.get();
    }
    e1.shutdown();
    return total;
}

这是 Callable

class Count implements Callable<Integer> {
//where the processing code is
}

所以当我运行这个程序时,它只使用了我的 CPU 的 12.5%,而这只是一个线程......各位有什么想法吗?

谢谢

【问题讨论】:

  • 在 ExecutorService.submit(callable) 之后立即调用 Future.get() 没有任何意义。它就像 callable.call() 的同步调用一样工作,但是在不同的线程上,这意味着一些不必要的开销。让所有提交在一个循环中,所有在另一个循环中。

标签: java multithreading executorservice callable


【解决方案1】:

问题出在你的循环中:

for (int i = 0; i < coreCount; i++) {
    Future<Integer> result = e1.submit(new Count(coreCount, i, charlist));
    total += result.get();
}

它的作用是:

  • 提交计算
  • Future对象上调用get()等待计算完成
  • 然后进行循环的下一次迭代

因此,在每次迭代中,您的代码都在等待计算完成,然后再提交下一个。

您应该创建两个循环,一个用于提交计算,它将所有Future 对象存储在一个集合中,然后第二个循环对每个Future 对象调用get()

【讨论】:

    【解决方案2】:

    您必须保存 Future 对象,而不是在提交下一个之前等待每个对象。

    public static int choiceCount(List<Character> charlist) throws InterruptedException, ExecutionException {
    
        int coreCount = Runtime.getRuntime().availableProcessors();
        ExecutorService e1 = Executors.newFixedThreadPool(coreCount);
        int total = 0;
        List<Future<Integer>> futures = new ArrayList<>();
        // start all the tasks, before
        for (int i = 0; i < coreCount; i++) 
            futures.add(e1.submit(new Count(coreCount, i, charlist)));
        // notify the executor to stop when finished in case get() throws an exception
        e1.shutdown(); 
        // collecting the results.
        for (Future<Integer> future: futures)
            total += future.get();
        return total;
    }
    

    【讨论】:

      【解决方案3】:

      您应该创建一个List&lt;Callable&lt;Integer&gt;&gt; 列表,然后在将启动所有计算线程的执行程序上使用invokeAll

      List<Callable<Integer>> callables = new ArrayList<Callable<Integer>>();
      for (int i = 0; i < coreCount; i++) {
          callables.add(new Count(coreCount, i, charlist));
      }
      List<Future<Integer>> futures = executor.invokeAll(callables); //why is it e1?
      //Then you can wait for all computations to  finish by calling
      for (Future<Integer> future : futures) {
          Integer result = future.get(); //blocks for computation to finish.
          //do something with result
      }
      

      【讨论】:

      • 非常感谢!我有 e1 因为我只是在尝试不同的线程,但我把它改回来了。第一次使用多线程进行测试,遇到了很多问题:D 谢谢。这太棒了!
      • +0 这只是做与 Executor.submit() 完全相同的事情的另一种方式,请参阅 Jesper 的回答。
      • @PeterLawrey 感谢 +0。顺便说一句,您的答案只是 Jesper 答案的实现。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多