CompletableFuture runAsync与使用执行程序执行每个Runnable

时间:2018-08-22 07:43:45

标签: java multithreading email asynchronous java-8

最近,我正在尝试实现一个电子邮件服务,该服务可以同时向每个用户发送电子邮件。我当前的实现方式如下:

Highcharts.chart('container', {
    chart: {
        events: {
            load: function() {
                var points = this.series[0].points;
                Highcharts.each(points, function(point) {
                    point.dataLabel.attr({
                        y: 20
                    });
                });
            }
        }
    },
    series: [{
        color: 'rgba(0,0,0,0)',
        zIndex: 0,
        dataLabels: {
            enabled: true
        },
        data: [1, 4, 5, 2, 1, 7]
    }]
});

经过一些研究,我发现了一种使用Java 8 ExecutorService executor = Executors.newSingleThreadExecutor(); tasks.forEach(executor::execute); // Each task sends an email to an user executorService.shutdown(); // Reclaim all the resources 方法的新方法。使用这种方法,我做到了:

CompletableFuture.runAsync(...)

现在,对于正确性,可伸缩性以及解决问题的最现代/最新方法,我有些困惑,这是解决问题的最佳方法。

3 个答案:

答案 0 :(得分:2)

for key,group in df_grouped: df_mt = marche_type_jointure_grouped.get_group(key) #we take the corresponding group from the other dataframe index_har = list(group.heure_arrivee_reelle.index.values) #list of index of actual arrival times from df_grouped referring to key index_hdp = list(df_mt.heure_debut_periode.index.values) #list of index of beginning time of period from marche_type_jointure_grouped refering to key for i in index_hdp: for j in index_har: if df_mt.heure_fin_periode[i] >= group.heure_arrivee_reelle[j]: group.temps_trajet_mt[j] = df_mt.temps_trajet_sur_periode[i] index_har.remove(j) #so that I do not have to compare it again else: pass df_grouped.size().unstack() #so that I can see the result 将异步执行您的任务。

Executor.execute也异步执行任务,但是另外,返回一个CompletableFuture.runAsync(Runnable, Executor)对象,您可以使用该对象链接/插入更多相关任务。

(例如,发送电子邮件后,您要向自己发送通知以指示成功:

CompletableFuture

对于您的用例,没有什么不同。

为简单起见,您可以坚持使用第一版代码。

答案 1 :(得分:0)

后一种方法的优势在于,它为您提供了一个CompletableFuture对象,该对象可用于get执行该操作的结果,以确保该操作已完成并获取任何异常被动作抛出。

由于您似乎并不在乎这些,我想直接调用执行程序就可以了。

答案 2 :(得分:0)

两个解决方案几乎完全相同-它们都在执行程序上异步执行任务。对于这个小例子,没有什么区别,第一个例子更好,因为它不会创建不必要的CompletableFuture

但是,请说您拥有以下代码:

public class EmailSender {

    private final Logger log = LoggerFactory.getLogger(EmailSender.class);

    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public void sendEmails(Collection<String> emails) {
        // make and send emails
        Collection<Runnable> tasks = createEmailTasks(emails);

        // Send them using the executor and then log a message when all emails have been sent, but how?
    }
}

此处Java8和CompletableFuture为您带来了明显的优势:

// Create futures of all tasks
CompletableFuture[] futures = tasks.stream()
    .map(task -> CompletableFuture.runAsync(task, executor))
    .toArray(size -> new CompletableFuture[size]);

// Log a message when all tasks have completed
CompletableFuture.allOf(futures)
    .thenRunAsync(() -> log.info("Email batch sent successfully"), executor);

您还可以使用CompletableFuture的任何链接方法(例如.thenRun(Runnable).thenApply(Function<ReturnValue, NewReturnValue>)(如果您的任务具有返回值)来处理单个任务。

因此,对于您当前的示例来说,这并不重要,但是使用CompletableFuture更加灵活并且可以面向未来。