在线程中标记未来对象

Labeling future object in threading

我有一个 for 循环,我在其中调用 db 以获取学生的一些值。现在 for 循环需要很多时间。所以想用未来对象的执行者服务代替它。在函数开始时,我使用 executor.submit() 方法调用了 db。 我只是不确定如何找到返回的未来对象是针对那个我可以用于进一步步骤的特定学生。请在下面找到代码

下面的函数是从 for 循环中调用的,自从被每个学生调用以来总体上花费了很多时间:

public void getDbDetails(String student){
       //calling db
       if(dbDetails.studentName = "XYZ"){
          //function based on student ID
       }
}

使用执行器框架:

public void getStudentData(List<String> students){
   final List<Future<?>> futures = new ArrayList<>();
        for(String student: students){
            Future<?> future = executor.submit(() ->{
                //db call
            });
            futures.add(future);
        }
}

public void getDbDetails(String student){
//In this case how would i know whether future has returned details for this particular student??
if(dbDetails.studentName = "XYZ"){
              //function based on student ID
           }
}

是否可以使用 future.get() 并根据未来对象的 studentId 创建映射,然后在函数 getDbDetails() 中使用该映射来获取特定学生信息,如果到那时 future 还没有返回任何东西,那么使用 Thread.wait();?这种方法是否正确或其他任何可以作为最佳解决方案的方法?

主要问题是您的 return 任务价值是 void。相反,您应该定义一个 Callable,return 是一个值。

一些未经测试的代码的草稿:

public class StudentNameLookup implements Callable < String >
{
    private String studentId ;
    
    public StudentNameLookup ( String studentId ) 
    {
        this.studentId = studentId ;
    }
    
    public String call()
    {
        String studentName ;
        // … DB call, passing `this.studentId`, returning a value stored in `studentName` local var. 
        return studentName ;
    }
}

在 Java 16+ 中,为了简洁起见,我们可以使用 record

public record StudentNameLookup ( String studentId ) implements Callable < String >
{
    public String call()
    {
        String studentName ;
        // … DB call, passing `this.studentId`, returning a value stored in `studentName` local var. 
        return studentName ;
    }
}

根据个人喜好,我会建立一个任务列表。

List < Callable < String > > tasks = new ArrayList<>();
for( String studentId : studentIds )
{
    Callable < String > task = new StudentNameLookup( studentId ) ;
    tasks.add( task ) ;
}

Submit all the tasks 到执行程序服务。你会得到一份期货清单。

您的期货的参数化类型(尖括号)将是您在 Callable.

上声明的 return 值的类型
ExecutorService es = Executors. … ;
List < Future < String > > futures = es.invokeAll( tasks ) ;

然后进行通常的执行器服务工作。关机,等待终止。之后,您知道所有提交的任务都已处理。

循环你的期货清单。测试每个 future 以查看它是否成功,然后检索其结果。

String studentName = future.get() ;

阅读 Java文档并在 Stack Overflow 中搜索样板文件。

如果您想要 return 学生 ID 以及检索到的学生姓名,请更改您的 return 类型。而不是 return 仅仅 String,return 一个你发明的类型的对象,一个包含 id 和 name 的类型。

public record Student ( String id , String name ) {}

将上面代码中的参数化类型(尖括号)从 < String > 更改为 < Student >