执行器服务返回错误的响应



我正在从基于学生ID的执行器服务提交方法的调用列表中创建未来列表。服务的响应不是为所有学生id返回的。它运行了正确的次数,但是在服务调用中使用的studentId不是第一个就是最后一个。它忽略了中间的部分。请检查下面的代码

private List<Student> studentTask() {
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Future<List<Student>>> tasks = new ArrayList<>();
for(int studentNumber = 1; studentNumber <= 10; studentNumber++) {
Callable<List<Student>> task = new StudentService(studentNumber);
Future<List<Student>> recordTask = executor.submit(task);
tasks.add(recordTask);
}
try {
for (Future<List<Student>> future : tasks) {
List<Student> student = future.get();
//...
}
return //studentList;
} catch (Exception e) {
}
}
private class StudentService implements Callable<List<Student>>{
private int studentId;

StudentService(int studentId){
this.studentId = studentId;
}

public List<Student> call(){
return getStudentNames(this.studentId);
}
}
public class Student{
private String studentName;
private int StudentId;
//Parameterized Constructor
}
private List<Student> getStudentNames(int studentId){
List<Student> studentList = // db call returning all student with 
// respect to studentId.
return studentList;
}

在下面的代码中,服务被调用了10次,但只有学生Id110和。无法获得2的结果到9这会导致一个不准确的结果。需要帮助理解如果我在这里错过了什么。

您的代码错误到无法编译的程度,正如我在注释中所指出的那样。您还省略了一些可能很重要的代码。所以我不能准确诊断出你有什么问题。因此,我将以我自己的风格修改你的代码,并使其工作。

与其尝试填充Future对象的列表,不如填充任务列表,RunnableCallable对象。然后可以调用ExecutorService#invokeAll来提交所有的任务。您将返回Future对象列表,以跟踪您提交的任务的完成情况。

首先,让我们将Student类定义为一个记录。

record Student( int number , String name ) { }

在我看来,你在StudentService类中混合了两种不同的责任。这门课应该只专注于掌握学生的数据。该类不应该是Callable。单独定义Callable,并将StudentService对象传递给它的构造函数。

注意,我们返回一个Optional。如果调用程序提供无效的学生ID,则返回空的Optional而不是空指针。

class StudentService
{
private Set < Student > students;
StudentService ( )
{
this.students =
Set.of(
new Student( 1 , "Alice" ) ,
new Student( 2 , "Bob" ) ,
new Student( 3 , "Carol" ) ,
new Student( 4 , "Davis" ) ,
new Student( 5 , "Ernestine" ) ,
new Student( 6 , "Frank" ) ,
new Student( 7 , "Gail" ) ,
new Student( 8 , "Harold" ) ,
new Student( 9 , "Iris" ) ,
new Student( 10 , "Jean-Luc" )
);
}
synchronized Optional < Student > fetchStudentById ( final int id )
{
return this.students.stream().filter( student -> student.id() == id ).findAny();
}
}

注意在上面的代码中fetchStudentById被标记为synchronized。我们知道这个方法将被跨线程调用。这里的当前实现可能是线程安全的,通过流式传输一个不可修改的List。但是在实际工作中,这种查找可能不是线程安全的。因此,我们将其标记为synchronized,以确保线程安全。

如果您对上面代码中的流感到不舒服,那么您可以使用传统的循环来实现相同的效果。使用流可以使代码更简洁,但是这里使用流是而不是重要的。

定义我们的任务,一个按ID查找学生的Callable,并返回一个Optional < Student >。我们将StudentService对象传递给它的构造函数,用于实际查找学生。然后我们传递了想要的学生的id。

class StudentFindingTask implements Callable < Optional < Student > >
{
private final StudentService studentService;
private final int studentId;
public StudentFindingTask ( final StudentService studentService , int studentId )
{
this.studentService = studentService;
this.studentId = studentId;
}
@Override
public Optional < Student > call ( ) throws Exception
{
return this.studentService.fetchStudentById( this.studentId );
}
}

现在我们已经准备好了。

实例化一个StudentService对象,供我们所有的任务使用。

StudentService studentService = new StudentService();

建立任务对象列表。将服务和id传递给每个服务。

int limit = 10;
List < StudentFindingTask > tasks = new ArrayList <>( limit );
for ( int studentId = 1 ; studentId <= limit ; studentId++ )
{
tasks.add( new StudentFindingTask( studentService , studentId ) );
}

准备executor服务,以及我们希望它填充的Future对象列表。

ExecutorService executorService = Executors.newFixedThreadPool( 5 );
List < Future < Optional < Student > > > futures;

将所有这些任务提交给执行器服务。

try { futures = executorService.invokeAll( tasks ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }

关闭执行器服务,等待结果。以下是取自Javadoc的样板代码,稍作修改。

executorService.shutdown(); // Stop accepting task submissions.
try
{
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{
executorService.shutdownNow(); // Cancel currently executing tasks
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{ System.err.println( "Pool did not terminate" ); }
}
}
catch ( InterruptedException ex )
{
executorService.shutdownNow();
Thread.currentThread().interrupt();
}

最后,通过检查每个Future对象来报告任务的结果。在实际工作中,您可能会询问未来的完成状态,但我将把它留给读者作为练习。

for ( Future < Optional < Student > > future : futures )
{
try { System.out.println( future.get() ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); } catch ( ExecutionException e ) { throw new RuntimeException( e ); }
}

运行时。

Optional[Student[id=1, name=Alice]]
Optional[Student[id=2, name=Bob]]
Optional[Student[id=3, name=Carol]]
Optional[Student[id=4, name=Davis]]
Optional[Student[id=5, name=Ernestine]]
Optional[Student[id=6, name=Frank]]
Optional[Student[id=7, name=Gail]]
Optional[Student[id=8, name=Harold]]
Optional[Student[id=9, name=Iris]]
Optional[Student[id=10, name=Jean-Luc]]

最新更新