Java MultiThread:意外的执行时间

时间:2018-01-08 14:04:23

标签: java multithreading

我目前正在检查Java中多线程的行为,并且我得到了意想不到的结果。

这就是我正在做的事情:

  1. 生成50个随机邻接矩阵,大小为600x600和 将它们保存为.txt文件
  2. 阅读这些矩阵并使用N运行Floyd Warshall算法 线程(从1到3)没有同步。每个线程运行 50个矩阵的算法。
  3. 这是我得到的结果(N个线程的总执行时间):

    200 x 200的50个矩阵:

    • 使用1个线程:~483 ms
    • 使用2个主题:~615 ms
    • 使用3个主题:~741 ms

    600 x 600的50个矩阵:

    • 1个线程:~9500 ms
    • 使用2个主题:~15389 ms
    • 使用3个主题:~16383 ms

    1000x1000的50个矩阵:

    • 使用1个线程:~43140 ms
    • 使用2个主题:~61408 ms
    • 使用3个主题:~76219 ms

    对于1,2或3个线程,时间是否应该或多或少相同? 它为什么会增加?

    这是运行N个线程的方法:

    private static void runThreads(List<int[][]> graphs, int nThreads) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(nThreads);
        Collection<Callable<String>> callables = new ArrayList<Callable<String>>();
    
        for(int i = 0; i < nThreads; i++) {
            callables.add(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    for(int[][] graph: graphs) {
                        FloydWarshall f = new FloydWarshall(graph);
                        f.checkConsistency();
                    }
                    return null;
                }
            });
        }
    
        long startTime = System.currentTimeMillis();
    
        List<Future<String>> futures = executor.invokeAll(callables);
    
        executor.shutdown();
    
        long endTime   = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("Total time: " + totalTime  + " ms");        
    }
    

1 个答案:

答案 0 :(得分:0)

正如@ C-Otto的评论所说,你在多个线程上多次运行任务:

for(int i = 0; i < nThreads; i++) { // <-- n threads are created
    System.out.println("Running thread #" + (i+1));
    executor.submit(new Runnable(){
        public void run(){
             for(int[][] graph: graphs) { // <-- operating on the whole list
                  FloydWarshall f = new FloydWarshall(graph);
                  f.checkConsistency();
             }
        }
    });         
}

因此,在查看代码时,您所看到的行为与预期一致。因为您只是创建n个线程,这些线程全部同时执行整个列表。执行时间的缺点来自JVM必须加载的额外负载(例如,创建一个新的线程,执行整个算法等)。

但你可能想要的是平衡负载到n个线程,因此每个线程只能处理整个(1/nth)的一小部分。

因此,您可能需要定义一些逻辑来分割源(例如SpliteratorForkJoinPoolStreams),然后再次测量时间。