Java 多线程对象创建速度比单线程慢
我有一个基本的问题。当我创建1亿个哈希表时,如果在一个内核上创建,那么在我的机器上大约需要6秒(运行时=每个内核6秒)。如果我在12个核上进行多线程(我的机器有6个核,允许超线程),大约需要10秒(运行时=每个核112秒) 这是我使用的代码: MainJava 多线程对象创建速度比单线程慢,java,multithreading,Java,Multithreading,我有一个基本的问题。当我创建1亿个哈希表时,如果在一个内核上创建,那么在我的机器上大约需要6秒(运行时=每个内核6秒)。如果我在12个核上进行多线程(我的机器有6个核,允许超线程),大约需要10秒(运行时=每个核112秒) 这是我使用的代码: Main public class Tests { public static void main(String args[]) { double start = System.currentTimeMillis(); int nThre
public class Tests
{
public static void main(String args[])
{
double start = System.currentTimeMillis();
int nThreads = 12;
double[] runTime = new double[nThreads];
TestsThread[] threads = new TestsThread[nThreads];
int totalJob = 100000000;
int jobsize = totalJob/nThreads;
for(int i = 0; i < threads.length; i++)
{
threads[i] = new TestsThread(jobsize,runTime, i);
threads[i].start();
}
waitThreads(threads);
for(int i = 0; i < runTime.length; i++)
{
System.out.println("Runtime thread:" + i + " = " + (runTime[i]/1000000) + "ms");
}
double end = System.currentTimeMillis();
System.out.println("Total runtime = " + (end-start) + " ms");
}
private static void waitThreads(TestsThread[] threads)
{
for(int i = 0; i < threads.length; i++)
{
while(threads[i].finished == false)//keep waiting untill the thread is done
{
//System.out.println("waiting on thread:" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
公共类测试
{
公共静态void main(字符串参数[])
{
双启动=System.currentTimeMillis();
int=12;
double[]运行时=新的双[n次读取];
TestsThread[]threads=新的TestsThread[nThreads];
int totalJob=100000000;
int jobsize=总作业/n次读取;
对于(int i=0;i
线程
import java.util.HashMap;
import java.util.Map;
public class TestsThread extends Thread
{
int jobSize = 0;
double[] runTime;
boolean finished;
int threadNumber;
TestsThread(int job, double[] runTime, int threadNumber)
{
this.finished = false;
this.jobSize = job;
this.runTime = runTime;
this.threadNumber = threadNumber;
}
public void run()
{
double start = System.nanoTime();
for(int l = 0; l < jobSize ; l++)
{
double[] test = new double[65];
}
double end = System.nanoTime();
double difference = end-start;
runTime[threadNumber] += difference;
this.finished = true;
}
}
import java.util.HashMap;
导入java.util.Map;
公共类TestsThread扩展线程
{
int jobSize=0;
双[]运行时;
布尔完成;
int线程数;
TestsThread(int作业,双[]运行时,int threadNumber)
{
this.finished=false;
this.jobSize=job;
this.runTime=运行时;
this.threadNumber=threadNumber;
}
公开募捐
{
双启动=System.nanoTime();
对于(int l=0;l
我不明白为什么在多个线程中同时创建对象比在一个线程中串行创建要花费更长的时间。如果删除创建哈希表的行,这个问题就会消失。如果有人能在这方面帮助我,我将非常感激。如果你在6个内核上做这件事呢?超线程与拥有双核并不完全相同,因此您可能还想尝试实际内核的数量
此外,操作系统也不一定会将每个线程调度到它们自己的核心。更新:此问题与Java 1.7u40相关,并且已通过
Java 1.7u40解决。这对于Java1.8
来说从来都不是问题,因为Java8有一个完全不同的哈希表算法
由于您没有使用创建的对象,该操作将得到优化。因此,您只需要测量创建线程的开销。这肯定是开销越大,启动的线程越多
关于一个细节,我必须纠正我的回答,我还不知道:类Hashtable
和HashMap
有一些特殊之处。它们都在构造函数中调用sun.misc.Hashing.randomHashSeed(this)
。换句话说,它们的实例在构造期间逃逸,这对内存可见性有影响。这意味着它们的构造与ArrayList
不同,无法进行优化,多线程构造由于该方法内部发生的事情(即同步)而减慢
如前所述,这对于这些类来说是特殊的,当然还有这个实现(我的设置:1.7.0_13
)。对于普通类,这种代码的构造时间直接变为零
这里我添加了一个更复杂的基准代码。观察DO\u HASH\u MAP=true
和DO\u HASH\u MAP=false
之间的差异(当false
时,它将创建一个ArrayList
,而该列表没有这种特殊行为)
import java.util.*;
导入java.util.concurrent.*;
公共类AllocBench{
静态最终int NUM_线程=1;
静态最终int NUM_对象=100000000个/NUM_线程;
静态最终布尔DO_HASH_MAP=true;
公共静态void main(字符串[]args)引发InterruptedException、ExecutionException{
ExecutorService线程池=Executors.newFixedThreadPool(NUM_线程);
可调用任务=新的可调用任务(){
公共长途电话(){
返回doAllocation(NUM_对象);
}
};
long startTime=System.nanoTime(),cpuTime=0;
对于(未来的f:threadPool.invokeAll(Collections.nCopies(NUM_THREADS,task))){
cpuTime+=f.get();
}
长时间=System.nanoTime()-startTime;
System.out.println(“线程数:+NUM_线程”);
System.out.printf(“需要整个分配%.03f s%n”,时间*1e-9);
System.out.printf(“时间x numThreads%.03f s%n”,时间*1e-9*NUM_线程);
System.out.printf(“实时累计cpu时间%.03f s%n”,cpuTime*1e-9);
threadPool.shutdown();
}
静态长doAllocation(int numObjects){
long t0=System.nanoTime();
对于(int i=0;i,由于您所做的只是测量时间和搅动内存,您的瓶颈很可能是在L3缓存或到主内存的总线中。在这种情况下,协调线程之间的工作可能会产生太多的开销,这会更糟,而不是更好
这对于注释来说太长了,但是您的内部循环可以是
double start = System.nanoTime();
for(int l = 0; l < jobSize ; l++){
Map<String,Integer> test = new HashMap<String,Integer>();
}
// runtime is an AtomicLong for thread safety
runtime.addAndGet(System.nanoTime() - start); // time in nano-seconds.
double start=System.nanoTime();
对于(int l=0;ldouble start = System.nanoTime();
for(int l = 0; l < jobSize ; l++){
Map<String,Integer> test = new HashMap<String,Integer>();
}
// runtime is an AtomicLong for thread safety
runtime.addAndGet(System.nanoTime() - start); // time in nano-seconds.