为什么我的代码在Java中使用多线程时速度较慢?

为什么我的代码在Java中使用多线程时速度较慢?,java,multithreading,Java,Multithreading,所以我有一个程序,运行一系列不同的计算,然后在所有计算完成后返回一个结果 最初,我的代码是同步的,如下所示: public class MyApplication{ public static void main(String[] args) { doCalculation(1); doCalculation(2); doCalculation(3); doCalculation(4); doCalcula

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

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

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 */
    }
}
公共类MyApplication{
公共静态void main(字符串[]args){
List threads=new ArrayList();
添加(doCalculation(1));
添加(文档计算(2));
添加(文档计算(3));
添加(文档计算(4));
添加(文档计算(5));
添加(文档计算(6));
添加(文档计算(7));
添加(doCalculation(8));
用于(螺纹t:螺纹){
if(t.isAlive()){
试一试{
t、 join();
}捕捉(中断异常e){
System.out.println(“计算适合度的错误”);
}
}
}
/*打印结果*/
}
}

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

为了获得最佳并行性,线程的数量不能超过可用的CPU内核的数量,超出这个数量的一切只会造成上下文切换的开销。此外,创建线程的成本很高,因此仅完成一次计算就让线程死亡是一种巨大的浪费。相反,您应该依赖Java库对并行性的出色支持

我的建议是使用Java8StreamsAPI并将您的问题表述为并行流,例如

IntStream.range(1, 9).map(this::doCalculation).parallel().collect(Collectors.toList());
这将在公共ForkJoinPool上执行,默认情况下,该池的大小取决于CPU内核的数量


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

每个线程都有启动和加入的开销。如果线程所做的工作很重要,那么开销是值得的;但是如果
doccalculation
相当快,那么开销将超过它

一般来说,线程不会让事情进展得更快——它们只是让更多的事情同时进行。如果每个线程都有大量的工作,并且多个线程可以同时全速运行(这是多个CPU内核的帮助),那么这是值得的


如果每个
doccalculation
需要X个时间,并且您有8个时间(因此是8T开销,其中T是每个线程的开销量),那么如果
8T>8TX
,整个程序将需要更长的时间,也就是说,如果旋转8个线程的开销大于按顺序执行所有8个计算所需的工作量。

之前我不知道:O线程列表。有趣!doCalculation()可能不会花费足够长的时间来抵消线程创建的开销。在适当的方法中,线程不会为每个单独的计算而旋转,因此基本开销要小得多,并且来自任务切换和结果收集。@MarkoTopolnik是的,但从这个例子中可以看出,OP实际上是手动创建和启动线程的(尽管仔细阅读,他们从来没有真正调用过
t.start()
!),您所说的可能适用于OP的代码,但关键是他的方法可以大大改进,最终目标是通过并行加速。