我正在学习多线程并发现在多线程环境中减慢了Object.hashCode的速度,因为计算运行4个线程的默认哈希码与相同数量的对象的1个线程相比,它需要花费两倍的时间.
但根据我的理解,它应该花费相同的时间并行执行此操作.
您可以更改线程数.每个线程都有相同的工作量,所以你希望在我的四核机器上运行4个线程可能需要与运行单个线程大致相同的时间.
我看到4x只有2.3秒,而1x则看到.9秒.
我的理解是否有任何差距,请帮助我理解这种行为.
import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; public class ObjectHashCodePerformance { private static final int THREAD_COUNT = 4; private static final int ITERATIONS = 20000000; public static void main(final String[] args) throws Exception { long start = System.currentTimeMillis(); new ObjectHashCodePerformance().run(); System.err.println(System.currentTimeMillis() - start); } private final ExecutorService _sevice = Executors.newFixedThreadPool(THREAD_COUNT, new ThreadFactory() { private final ThreadFactory _delegate = Executors.defaultThreadFactory(); @Override public Thread newThread(final Runnable r) { Thread thread = _delegate.newThread(r); thread.setDaemon(true); return thread; } }); private void run() throws Exception { Callablework = new java.util.concurrent.Callable () { @Override public Void call() throws Exception { for (int i = 0; i < ITERATIONS; i++) { Object object = new Object(); object.hashCode(); } return null; } }; @SuppressWarnings("unchecked") Callable [] allWork = new Callable[THREAD_COUNT]; Arrays.fill(allWork, work); List > futures = _sevice.invokeAll(Arrays.asList(allWork)); for (Future future : futures) { future.get(); } } }
对于线程数4输出是
~2.3 seconds
对于线程计数1输出是
~.9 seconds
Svetlin Zare.. 6
我已经创建了一个简单的JMH基准来测试各种情况:
@Fork(1) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Measurement(iterations = 10) @Warmup(iterations = 10) @BenchmarkMode(Mode.AverageTime) public class HashCodeBenchmark { private final Object object = new Object(); @Benchmark @Threads(1) public void singleThread(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(2) public void twoThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(4) public void fourThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(8) public void eightThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } }
结果如下:
Benchmark Mode Cnt Score Error Units HashCodeBenchmark.eightThreads avgt 10 5.710 ± 0.087 ns/op HashCodeBenchmark.fourThreads avgt 10 3.603 ± 0.169 ns/op HashCodeBenchmark.singleThread avgt 10 3.063 ± 0.011 ns/op HashCodeBenchmark.twoThreads avgt 10 3.067 ± 0.034 ns/op
所以我们可以看到,只要没有线程而不是核心,每个哈希码的时间保持不变.
PS:正如@Tom Cools评论的那样 - 你在测试中测量分配速度而不是hashCode()速度.
我已经创建了一个简单的JMH基准来测试各种情况:
@Fork(1) @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Measurement(iterations = 10) @Warmup(iterations = 10) @BenchmarkMode(Mode.AverageTime) public class HashCodeBenchmark { private final Object object = new Object(); @Benchmark @Threads(1) public void singleThread(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(2) public void twoThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(4) public void fourThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } @Benchmark @Threads(8) public void eightThreads(Blackhole blackhole){ blackhole.consume(object.hashCode()); } }
结果如下:
Benchmark Mode Cnt Score Error Units HashCodeBenchmark.eightThreads avgt 10 5.710 ± 0.087 ns/op HashCodeBenchmark.fourThreads avgt 10 3.603 ± 0.169 ns/op HashCodeBenchmark.singleThread avgt 10 3.063 ± 0.011 ns/op HashCodeBenchmark.twoThreads avgt 10 3.067 ± 0.034 ns/op
所以我们可以看到,只要没有线程而不是核心,每个哈希码的时间保持不变.
PS:正如@Tom Cools评论的那样 - 你在测试中测量分配速度而不是hashCode()速度.