【问题标题】:Delayed ExecutorService with manual start手动启动的延迟 ExecutorService
【发布时间】:2020-07-28 05:28:28
【问题描述】:

我有一个简单的 ExecutorService(通过 Executors.newSingleThreadExecutor())用于提交 Runnables 到。但是,我想将这些 Runnables 排队,并且只有在我手动通知它时才让 ExecutorService 执行它们(仅一次)。

注意我不是想把它变成一个同步过程——我只是想控制提交的 Runnables 的执行时间

【问题讨论】:

    标签: java android executorservice runnable completable-future


    【解决方案1】:

    由于您用 标记了您的问题,我想您正在考虑以下方向:

    ExecutorService es = Executors.newSingleThreadExecutor();
    
    CompletableFuture<Void> trigger = new CompletableFuture<>();
    
    // submit your jobs
    trigger.thenRunAsync(aRunnable, es);
    trigger.thenRunAsync(anotherRunnable, es);
    trigger.thenRunAsync(yetAnotherRunnable, es);
    
    // and later-on
    trigger.complete(null);
    // now all Runnables will get submitted and executed
    
    
    // you can use the same construct even after trigger point
    // then, the runnable will get submitted immediately
    
    trigger.thenRunAsync(aRunnable, es);
    
    // finally
    es.shutdown();
    

    但请注意,这不会维持提交顺序,因为所有操作都被建模为仅取决于触发器。如果你需要保持订单,你可以使用类似的东西

    CompletableFuture<Void> trigger = new CompletableFuture<>();
    CompletableFuture<Void> order = trigger;
    
    // submit your jobs
    order = order.thenRunAsync(aRunnable, es);
    order = order.thenRunAsync(anotherRunnable, es);
    order = order.thenRunAsync(yetAnotherRunnable, es);
    
    // and later-on
    trigger.complete(null);
    

    由于这只会在前一个作业完成后提交下一个作业,因此您必须小心关闭ExecutorService 的时间。但您可以使用order.join() 等待所有作业完成。

    此外,当不同的线程可能以这种方式提交作业时必须小心,因为这样,order 变量的更新必须以线程安全的方式完成。

    【讨论】:

      【解决方案2】:

      使用invokeAll() 很简单。你需要创建一个CollectionCallables:

              List<Callable<?>> tasks = ...;
                                         
              executor.invokeAll(tasks);
      }
      

      invokeAll() 等到所有 Callables 完成。

      【讨论】: