【问题标题】:Implementing threads/callable adds 50% to my execution time, why is this?实现线程/可调用会增加 50% 的执行时间,这是为什么呢?
【发布时间】:2021-06-09 13:33:02
【问题描述】:

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

我试图通过调用我的函数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();
   }
}

【问题讨论】:

  • 您正在创建 两个 列表,两个列表都由 单个 线程填充。您可能想要创建一个由 两个 线程填充的 单个 列表?
  • 无关:遵循 java 命名约定。类名采用大写字母,而不是 SOLIDUPPERCASE。您在那里所做的事情极具误导性,因为人们很容易假设 DATA 不是类名而是泛型类型参数。
  • @Lino 我的意图是同时填写 2 个单独的列表,所以在并行中。然后看看它有多快。 2 个任务 2 个线程

标签: java multithreading concurrency multitasking


【解决方案1】:

Callable 是要执行的任务。您的代码只有一个Callable,因此只能在一个线程上执行。

即使您创建了一个包含两个线程的ThreadPool,但由于您只有一个任务,因此可以保证其中一个线程处于空闲状态。

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

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

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

【讨论】:

  • 谢谢回复,我试试看!
【解决方案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");
    }

【讨论】:

  • 非常感谢您提供的代码示例!我无法让它工作,所以这很有帮助。
猜你喜欢
  • 1970-01-01
  • 2016-10-23
  • 2017-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多