为什么我的代码在Java中使用多个线程会变慢?

时间:2014-12-05 21:52:36

标签: java multithreading

所以我有一个程序运行一系列不同的计算,然后在完成所有计算后返回结果。

最初我的代码是同步的,如下所示:

public class MyApplication{

    public static void main(String[] args) {
        doCalculation(1);
        doCalculation(2);
        doCalculation(3);
        doCalculation(4);
        doCalculation(5);
        doCalculation(6);
        doCalculation(7);
        doCalculation(8);

        /* Print result */
    }
}

我认为在新线程中运行这些计算会更有效,所以现在我有类似的东西,

public class MyApplication{
    public static void main(String[] args) {
        List<Thread> threads = new ArrayList<Thread>();
        threads.add(doCalculation(1));
        threads.add(doCalculation(2));
        threads.add(doCalculation(3));
        threads.add(doCalculation(4));
        threads.add(doCalculation(5));
        threads.add(doCalculation(6));
        threads.add(doCalculation(7));
        threads.add(doCalculation(8));

        for(Thread t : threads){
            if(t.isAlive()){
                try{
                    t.join();
                } catch(InterruptedException e) {
                    System.out.println("Error calculating fitness");
                }
            }
        }

        /* Print result */
    }
}

对不起,我是线程的完全初学者。如果我不得不猜测我会假设我已经产生了两个新线程(我的应用程序中有大约50个计算),但任何建议都会非常感激!

2 个答案:

答案 0 :(得分:5)

每个线程都有开始和加入的开销。如果线程所做的工作很重要,那么开销是值得的;但如果doCalculation非常快,那么开销就会超过它。

一般来说,线程不会让事情变得更快 - 它们只会让更多事情一次性发生。如果每个线程有大量的工作,并且多个线程可以同时以全速运行(这是多个CPU核心帮助的地方),那么这是值得的。

如果每个doCalculation花费X时间,并且你有8个(因此8T开销,其中T是每个线程的开销量),那么如果8T > 8TX整个程序将花费更长的时间 - 也就是说,如果旋转8个线程的开销大于按顺序完成所有8个计算的工作量。

答案 1 :(得分:3)

为了获得最佳的并行性,线程数不得超过可用的CPU核心数,除此之外的所有内容只会从上下文切换中产生开销。此外,线程的创建成本很高,因此在完成一次计算后让线程死亡是一个很大的浪费。相反,您应该依赖Java库附带的并行性的出色支持。

我的建议是使用Java 8 Streams API并将您的问题表示为并行流,例如

IntStream.range(1, 9).map(this::doCalculation).parallel().collect(Collectors.toList());

这将在公共ForkJoinPool上执行,默认情况下根据CPU核心数量进行调整。

我认为你并行化的整体工作需要花费大量时间在一个内核上(至少几毫秒)并且不涉及I / O,因为这些是并行化的基本前提条件值得。如果没有足够的工作要做,任务切换到线程和结果收集的开销将消除并行处理的任何优势。如果执行任何I / O操作,则会发生阻塞,在CPU空闲时占用一个线程。