【问题标题】:How to use ExecutorService of java concurrent programming?java并发编程的ExecutorService如何使用?
【发布时间】:2011-02-25 10:09:23
【问题描述】:

我正在使用下面的代码在远程服务器上上传图片。当我在下面使用时,它会将所有图片同时上传到远程服务器上。

List<Future<String>> futureList = new ArrayList<Future<String>>();
ExecutorService execService = Executors.newFixedThreadPool(Images.size());
for (IImage image : Images) { 
  try {
    //execService.execute(lServerRequest.new uploadImages(image.getDataPath(),image.getDisplayName()));
    singleFuture = execService.submit(lServerRequest.new uploadImages(image.getDataPath(),image.getDisplayName()));
    //Log.d("","singleFuture -------"+singleFuture.get());
    futureList.add(singleFuture);
    Log.d("","futureList Size:"+futureList.size());
  } catch(Exception e){
    execService.shutdown();
  }

每当我使用下面的代码时

   singleFuture = execService.submit(lServerRequest.new uploadImages(image.getDataPath(),image.getDisplayName()));
//Log.d("","singleFuture -------"+singleFuture.get());
    futureList.add(singleFuture);

将所有未来对象添加到futurelist,立即从runnable返回(在runnable中等待,直到所有图像上传完成(后台上传处理正在进行))

但是每当我在上面的代码中取消注释时,在成功上传每个图像后,它都会从 runnable 返回。

singleFuture = execService.submit(lServerRequest.new uploadImages(image.getDataPath(),image.getDisplayName()));
Log.d("","singleFuture -------"+singleFuture.get());
futureList.add(singleFuture);

我的代码有什么问题吗?是否可以一次连接更多远程服务器或服务器上有任何负载?如何使用并行编程java上传图像?请指导?

submit()execute() 函数效果一样吗?

【问题讨论】:

    标签: java concurrent-programming


    【解决方案1】:

    当您致电singleFuture.get() 时,您正在等待操作完成。所以循环不会继续执行下一条语句,直到这条语句返回结果。

    您需要在第一个循环中提交您的任务,然后,另一个循环应遍历列表中的结果 future.get() 以使其异步

    来自@andersoj 的回答;

    池大小应该与您的 CPU 内核有关。不是您手头的图像数量。假设您有 2 个核心 CPU,则图像上传 io 时间的系数为 5(只是我猜测的系数)。

    POOL_SIZE = NUM​​_OF_CPU_CORE*系数;

    【讨论】:

    • +1:哎呀!我完全错过了日志调用中的.get()。叹。很好的收获。
    【解决方案2】:

    submit() 将任务添加到队列并返回Futureexecute() 不返回 Future。另见here。您观察到的不同排序可能是 submit() 内部发生的额外管理的副作用,并且可能无关紧要。 (但请参阅@fmucar 的回答...)

    不确定您的问题是什么...

    根据您要上传的图像数量来调整线程池的大小实际上没有意义——可能少量线程就足够了,因为您只是试图保持一些 TCP 流的馈送。每张图片一个线程,如果图片列表很大,不会给你买任何东西。

    如果您收集Futures 只是为了知道上传何时完成,请考虑以下方法之一:

    编辑添加:很好,@fmucar,在记录器行中对.get() 的调用强制顺序,因此线程池是一种浪费。

    invokeAll() 示例

    这里试图给你一个invokeAll() 的例子;不确定它是否与您的代码完全匹配。

    final int poolSize = ...;  // see fmucar's answer
    final ExecutorService execService = Executors.newFixedThreadPool(poolSize);
    final List<Callable<>> uploadTasks = new ArrayList<Callable<>>();
    
    for (final IImage image : Images) { 
       // maybe I got this wrong?  Can't quite parse your code.
       Callable<String> uTask = new uploadImages(image.getDataPath(),image.getDisplayName());
       uploadTasks.add(uTask);
    }
    // this thread will block here until all the tasks complete
    final List<Future<String>> futureList = execService.invokeAll();
    // or you can toss the result entirely if the futures don't matter.    
    

    【讨论】:

    • 您能否详细说明,选择哪种方法(submit()/execute())在远程服务(服务器)上上传图像?或者任何概念是用于将大尺寸图像上传到远程服务器?
    • 两者在逻辑上应该是等价的;唯一的决定因素是您是否要使用Callables 和/或Futures。如果您不在乎(即Runnables 工作正常,并且您不需要将来的完成句柄),那么就没有真正的区别。
    • @andersoj:感谢您的建议。但是您建议使用 invokeall() 和 completeservice()。我可以使用一个或两个吗?请给我任何示例代码的链接?
    • @ADIT:使用invokeAll()CompletionService;可能两者都不是。前者非常非常简单有效。后者更灵活也更复杂。出于您的目的,我建议使用前者,只要此“图像上传”不是从 UI 线程或类似线程启动的——invokeAll() 的效果是 block 当前线程,直到所有附属任务完成。在某些情况下非常有用。如果这是在 UI 线程或任何其他有更多业务要做的事情,那么您将需要 CompletionService
    • @ADIT:例如,参见 stackoverflow.com/questions/5013999/…stackoverflow.com/questions/4912228/…,它们具有 sn-ps。对于invokeAll(),这很简单,但请参阅我的帖子:stackoverflow.com/questions/4470492/…。如果您可以从您的应用中提供更多示例代码,我也许可以为您提供一个完整的示例(但告诉我您想看哪个。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 2016-09-23
    • 1970-01-01
    相关资源
    最近更新 更多