实施 threads/callable 会使我的执行时间增加 50%,这是为什么?

Implementing threads/callable adds 50% to my execution time, why is this?

我目前正在学习多线程,但我在理解我的代码中出了什么问题时遇到了一些问题。

我试图通过调用我的函数 threadPopulateList() 来用随机数据填充两个列表。以我的理解,这应该并行启动两个线程,因为我调用了该方法两次。

但是,使用 threadmethod 时,我的执行时间增加了 ~50%。

代码:

public class Main {


public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
    long start=System.currentTimeMillis();

    /**Populate lists after eachother gives --> 4211 ms */
    //        List<DATA>list1normal = populateNormal(9999999);
    //        List<DATA>list2normal = populateNormal(9999999);

    /**Populate list simoultaniously/parralel --> 6500ms???*/
    List<DATA>list1normal = threadPopulateList(9999999);
    List<DATA>list2normal = threadPopulateList(9999999);

    long stop = System.currentTimeMillis();
    long executionTime = stop-start;
    System.out.println(executionTime+" ms");

}

/**Method to populate list*/
static List<DATA> populateNormal(int amount){
    List<DATA>data = new ArrayList<>();
    Random rn = new Random();
    for (int i = 0; i < amount; i++) {
        data.add(new DATA(rn.nextInt(1000),rn.nextInt(1000), rn.nextInt(1000)));
    }
    return data;
}

/**Method to start a thread for each call so list will populate simoultiously*/
static List<DATA> threadPopulateList(int amount) throws InterruptedException, ExecutionException {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    List<DATA> data = new ArrayList<>();
    Random rn = new Random();
    Callable<List<DATA>> callable = () -> {
        for (int i = 0; i < amount; i++) {
            data.add(new DATA(rn.nextInt(1000), rn.nextInt(1000), rn.nextInt(1000)));
        }
        return data;
    };
    Future<List<DATA>> result = executor.submit(callable);
    executor.shutdown();
    return result.get();
   }
}

Callable是要执行的任务。你的代码只有一个Callable所以它只能在一个线程上执行。

即使您创建了一个包含两个线程的ThreadPool,但由于您只有一个任务,所以其中一个线程肯定是空闲的。

此外,您填写了两次列表,因此您的一项任务将是您填写一次列表时的两倍。

我会尝试创建两个 Callable 来处理列表中 1/2 的数据;然后安排他们两个。两者都完成后,将结果合并到最终的“输出”列表中。

您的解决方案只增加 50% 而不是 100% 的时间的原因是因为您的基准可能包括启动 JVM 和开始处理的时间。这意味着您对原始程序的整体分解可能是“执行时间 = 启动时间 + 处理时间”,其中启动时间约为执行时间的 1/2。

您实际上是在创建两个具有内部线程的序列化任务,但实际上并没有执行任何操作。如果你想并行化,你需要尝试更多类似这样的东西:

public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        long start=System.nanoTime();
        int amount = 9999999;
        populateNormal(amount);
        populateNormal(amount);
        long stop = System.nanoTime();
        System.out.println("Normal execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop - start)+"ms");
        
        ExecutorService executor = Executors.newFixedThreadPool(2);
        start = System.nanoTime();
        final CountDownLatch latch = new CountDownLatch(2);
        executor.submit(new Runnable() {
            
            @Override
            public void run() {
                populateNormal(amount);
                latch.countDown();
            }
        });
        
        executor.submit(new Runnable() {
            @Override
            public void run() {
                populateNormal(amount);
                latch.countDown();
            }
        });
        latch.await();
        stop = System.nanoTime();
        executor.shutdown();        
        System.out.println("Threaded execution completed in " + TimeUnit.NANOSECONDS.toMillis(stop-start)+"ms");
    }