Java 为什么两个线程的计算速度比一个线程慢?

Java 为什么两个线程的计算速度比一个线程慢?,java,multithreading,cpu-cores,Java,Multithreading,Cpu Cores,我正在开发一个用Java开发的基准测试应用程序。我在主线程上运行此代码两次,然后在两个单独的线程中运行一次: if (testing == null) { testing = new byte[TEST_SIZE][TEST_SIZE][TEST_SIZE]; } for (int x = 0; x < TEST_SIZE; x ++) { for (int y = 0; y < TEST_SIZE; y ++) { for (int z = 0;

我正在开发一个用Java开发的基准测试应用程序。我在主线程上运行此代码两次,然后在两个单独的线程中运行一次:

if (testing == null) {
    testing = new byte[TEST_SIZE][TEST_SIZE][TEST_SIZE];
}

for (int x = 0; x < TEST_SIZE; x ++) {
    for (int y = 0; y < TEST_SIZE; y ++) {
        for (int z = 0; z < TEST_SIZE; z ++) {
            testing[x][y][z] = (byte)RANDOM.nextInt(100);
        }
    }
}

if (finished == Test.LOOP_COUNT - 1) {
    testing = null;
}
我在某个地方读到一篇文章,说运行非常快的操作的两个线程的性能不如一个线程,但是两个线程在要求更高的操作上的性能要优于一个线程。我认为情况并非如此,因为每个循环都要求很高。我能想到的唯一原因是线程实际上并没有在它们自己的内核上运行。这可能是问题所在吗?我有一个2核4线程Intel core i7-3537U

编辑:

测试等级:

package net.jibini.park.tests;

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 *
 * @author zgoethel12
 */
public abstract class Test {

public static final Random RANDOM = new Random();
public static final int LOOP_COUNT = 2;

public static final CopyOnWriteArrayList<Test> tests = new CopyOnWriteArrayList<Test>();

public int finished = 0;
public int longestTime = 0;
public double timeSum = 0;

static {
    RANDOM.setSeed(481923);
    tests.add(new TestArray());
}

public abstract String getName();

public void runTest(final boolean multithread) {

    new Thread(new Runnable() {
            @Override
            public void run() {
                finished = 0;
                longestTime = 0;
                timeSum = 0;

                if (multithread) {
                    for (int i = 0; i < LOOP_COUNT; i ++) {
                        final int f = i;
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                doLoop(f + 1);
                                Thread.currentThread().interrupt();
                            }
                        }).start();
                    }
                } else {
                    for (int i = 0; i < LOOP_COUNT; i ++) {
                        doLoop(i + 1);
                    }
                }

                while (finished < LOOP_COUNT) {
                    System.out.print("");
                }

                System.out.println("Finished in " + (multithread ? longestTime : (int)timeSum) + " seconds.");
                Thread.currentThread().interrupt();
            }
    }).start();

}

public void doLoop(int id) {

    long start = System.nanoTime();
    doTest(id);
    handleLoopFinish(id, start);

}

public abstract void doTest(int id);

public void handleLoopFinish(int id, long start) {

    long current = System.nanoTime();
    long difference = current - start;
    double seconds = (double)difference / 1000000000;
    if (seconds > longestTime) {
        longestTime = (int)seconds;
    }
    timeSum += seconds;
    System.out.println("Loop #" + id + " finished in " + seconds + " seconds.");
    finished ++;

}

}
package net.jibini.park.tests;
导入java.util.Random;
导入java.util.concurrent.CopyOnWriteArrayList;
/**
*
*@作者zgoethel12
*/
公共抽象类测试{
公共静态最终随机=新随机();
公共静态最终整数循环计数=2;
公共静态最终CopyOnWriteArrayList测试=新建CopyOnWriteArrayList();
公共int finished=0;
公共整数最长时间=0;
公共双时隙=0;
静止的{
随机设定种子(481923);
tests.add(newtestarray());
}
公共抽象字符串getName();
公共void运行测试(最终布尔多线程){
新线程(newrunnable()){
@凌驾
公开募捐{
完成=0;
最长时间=0;
timeSum=0;
if(多线程){
for(int i=0;i最长时间){
最长时间=(整数)秒;
}
timeSum+=秒;
System.out.println(“循环#“+id+”在“+秒+秒”内完成);
已完成++;
}
}
阵列测试:

package net.jibini.park.tests;

/**
 *
 * @author zgoethel12
 */
public class TestArray extends Test {

public static final int TEST_SIZE = 512;

byte[][][] testing = null;

@Override
public void doTest(int id) {

    if (testing == null) {
        testing = new byte[TEST_SIZE][TEST_SIZE][TEST_SIZE];
    }

    for (int x = 0; x < TEST_SIZE; x ++) {
        for (int y = 0; y < TEST_SIZE; y ++) {
            for (int z = 0; z < TEST_SIZE; z ++) {
                testing[x][y][z] = (byte)RANDOM.nextInt(100);
            }
        }
    }

    if (finished == Test.LOOP_COUNT - 1) {
        testing = null;
    }

}

@Override
public String getName() {
    return "Array Handling";
}

}
package net.jibini.park.tests;
/**
*
*@作者zgoethel12
*/
公共类TestArray扩展了测试{
公共静态最终整数测试_SIZE=512;
字节[]测试=空;
@凌驾
公共void doTest(int-id){
如果(测试==null){
测试=新字节[测试大小][测试大小][测试大小];
}
对于(int x=0;x
启动第二个线程(取决于您选择执行多线程处理的库)需要大量开销,而且您似乎正在执行的操作(取决于测试大小)可能由一个CPU非常有效地执行,因为您以连续方式遍历内存中的阵列

我在课程作业中被告知,内置线程Java库的开销比ForkJoin框架要大得多,所以使用该库可能会得到更多预期的结果

作为资源,我在并发类中使用了一个很好的网站:


如下文所述,进行热身跑步时要小心。它们是确保您看到好处的关键。我们试着跑100次,热身时跑10次,以确保你获得一些好的平均成绩。由于上下文切换/其他计算机过程可能会增加试验的可变性,因此多次试验的平均值非常有帮助

您似乎只使用了一个
随机对象。恐怕这是两个线程之间共享的,这可能会使它们非常慢


尝试使用。

显示多线程代码。如果您使用了相同的,但在每个线程上都启动了它,那么线程必须为写入RAM中相同对象的权限而斗争-这就是延迟。很可能您的基准测试是错误的,例如忽略了预热,尝试使用并查看是否仍然得到这些结果。如何在两个线程之间分割作业?您的
TestArray
Test
类似乎有很多死代码(即未实际使用的变量),JIT编译器可以简单地消除这些死代码。正如@the8472所建议的,对于可靠的微基准测试,您最好使用一个好的框架。谢谢您的回复。我需要将线程作为基准测试的一部分,将
TEST\u SIZE
的值设置得太高会导致内存不足。我已经为它投入了6GB。我将研究ForkJoin。问题是使用Random的单个实例。我把它修好了,处理的时间大约减少了一半。实际上,我在java 6中工作,所以我刚刚创建了新的实例。你应该真正考虑升级,特别是如果你想要更好的性能的话,JVM内部的很多小的改变会带来巨大的变化。
package net.jibini.park.tests;

/**
 *
 * @author zgoethel12
 */
public class TestArray extends Test {

public static final int TEST_SIZE = 512;

byte[][][] testing = null;

@Override
public void doTest(int id) {

    if (testing == null) {
        testing = new byte[TEST_SIZE][TEST_SIZE][TEST_SIZE];
    }

    for (int x = 0; x < TEST_SIZE; x ++) {
        for (int y = 0; y < TEST_SIZE; y ++) {
            for (int z = 0; z < TEST_SIZE; z ++) {
                testing[x][y][z] = (byte)RANDOM.nextInt(100);
            }
        }
    }

    if (finished == Test.LOOP_COUNT - 1) {
        testing = null;
    }

}

@Override
public String getName() {
    return "Array Handling";
}

}