java lambda 局部变量,Java中的异步Lambda如何将局部变量

本文探讨如何使用CompletableFuture创建异步任务,并通过whenComplete回调测量任务运行时间。关键点在于理解lambda表达式中变量的拷贝行为,确保在多线程环境下打印的时间准确。作者解释了变量捕捉的概念,强调只有final或effectively final变量会被安全地复制,从而避免并发问题。
摘要由CSDN通过智能技术生成

I have a method (can be concurrently called by different threads) that creates an asynchronous task and returns a CompletableFuture. I want to measure the time it takes to run the task by chaining it with a whenComplete(...) as follows:

public CompletableFuture createTask(...) {

CompletableFuture result = ...;

final long startTime = System.currentTimeMillis();

result.whenComplete((res, err) -> {

System.out.println(System.currentTimeMillis() - startTime);

}

}

The lambda that I pass in will be executed asynchronously and the method that I wrote will also be multi-threaded. Will this lambda be able to print out the accurate time? How does Java handle variable scope when the lambda gets executed asynchronously by a different thread?

解决方案

When a lambda captures a variable, you can think of it as the lambda getting a copy of that variable's value. Because only final or effectively final variables can be captured, it is safe for lambdas to copy them. Their values won't change, so there's no danger of the copy being out of sync with the original variable.

Lambdas needn't be implemented with anonymous classes, but you can think of them conceptually as syntactic sugar for anonymous classes. Your whenComplete call is equivalent to:

long startTime = System.currentTimeMillis();

result.whenComplete(new BiConsumer() {

@Override public void accept(T res, U err) {

System.out.println(System.currentTimeMillis() - startTime);

}

});

The thing is, variable capturing isn't new with lambdas. Anonymous classes also capture variables, and they did it before lambdas came along. What happens is, they secretly stash away copies of captured variables. They get synthetic private fields to store those stashed values. The code above actually is more like this, if we make the synthetic field explicit:

long startTime = System.currentTimeMillis();

result.whenComplete(new BiConsumer() {

private final long _startTime = startTime;

@Override public void accept(T res, U err) {

System.out.println(System.currentTimeMillis() - _startTime);

}

});

Notice that once this anonymous BiConsumer is instantiated it stands on its own two feet. The body of accept() now refers to an instance variable, not to the captured variable. The anonymous object is not tied to the outer function, nor to the thread in which it was created. accept() can be called at any time and from any thread and will behave as one would expect, even if the original startTime variable is long since dead and buried.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值