如何访问线程lambda中的非final变量?

5lhxktic  于 2021-07-05  发布在  Java
关注(0)|答案(1)|浏览(492)

我需要在线程lambda中修改一个自定义对象,因为我需要执行一个操作并给它赋值。
问题是,当我在thread()中声明变量时,它不能从封闭函数返回。然后,如果我试图使它成为一个全局变量,并在线程中为它赋值,那就做不到了,因为lambda只允许在它们内部使用final或有效的final变量。
对此有什么解决方法/解决方案?

// Gives an undesired result 
 public class MeClass {
    public static Response response = new Response();

    // TODO: Make response specific to a method and not global

    public Response get(String endpoint) {
        new Thread(() -> {
            try {
                this.response = OffredUtil.makeGetRequest(endpoint);
            } catch (Exception e) {
                this.response.isException = true;
                Log.d(TAG, e.getMessage());
            }
        }).start();
        return this.response;
    }
    // Another method with similar function accessing response

}

所以我想宣布 response 在方法本身内部,但我不能这样做,因为只有最终变量可用。

// Gives an error
public Response get(String endpoint) {
        Response response = new Response();
        new Thread(() -> {
            try {
                response = OffredUtil.makeGetRequest(endpoint);
            } catch (Exception e) {
                this.response.isException = true;
                Log.d(TAG, e.getMessage());
            }
        }).start();
        return response;
pokxtpni

pokxtpni1#

假设这是允许的?你希望它会有什么回报?

// Warning! This is an example of what *NOT* to do.
//
public Response get(String endpoint) {
    Response response = new Response();
    new Thread(() -> {
        response = OffredUtil.makeGetRequest(endpoint);
    }).start();
    return response;
}

没理由这么想 response = OffredUtil.makeGetRequest(endpoint); 语句将一直执行到 return response; 声明。事实上,它可能要过一段时间才会被执行。
你真正想要的是;
为了你的 get(endpoint) 方法返回可变对象,以及
调用方等待新值被其他线程存储到可变对象中的一种方法。
java标准库为这种可变对象定义了一个接口:称为 java.util.concurrent.Future . 一 Future 有一个 get() 方法,该方法将在必要时等待,直到其他线程通过给它一个值来完成未来,然后 get() 将返回值。
最简单的使用方法是通过 CompletableFuture 班级:

import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
...
public Future<Response> get(String endpoint) {
    return CompletableFuture.supplyAsync(() -> {
       return OffredUtil.makeGetRequest(endpoint);
    });
}

打电话给这个 get(endpoint) 方法将任务提交给一个内置线程池,该线程池将执行给定的lambda表达式,然后它将返回一个 Future 这将由任务完成。
如果lambda产生一个值,那么它将成为 Future . 如果lambda抛出一个异常,那么将捕获该异常,并将异常对象存储在 Future 打电话的人 get(endpoint) 可以这样做:

...
Future<Response> fr = myClassInstance.get(endpoint);
doSomethingElseConcurrentlyWithThe_makeGetRequest_call(...);
try {
    Response r = fr.get();
    ...
} catch (Exception e) {
    o.response.isException = true;
    Log.d(TAG, e.getMessage());
}

相关问题