我正在根據學生 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 次,但僅針對學生 ID 1和10。無法獲得2到9的結果,導致結果不準確。如果我在這里遺漏任何東西,需要幫助來理解。
uj5u.com熱心網友回復:
如我的評論中所述,您的代碼錯誤到無法編譯的程度。你已經省略了一些可能很重要的代碼。所以我無法準確診斷你有什么問題。所以我會以我自己的風格修改你的代碼,并讓它作業。
我不會嘗試填寫Future物件串列,而是填寫任務串列,Runnable或者Callable物件。然后,您可以呼叫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為執行緒安全。
如果您對上面代碼中看到的流不滿意,請知道您可以使用常規回圈實作相同的效果。使用流可以簡化代碼,但這里使用流并不重要。
定義我們的任務, aCallable按 ID 查找學生,并回傳 a 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 ) );
}
準備執行器服務,以及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]]
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/485013.html
上一篇:在Rx中,處理執行緒安全是否是消費者(IObserver)的責任?
下一篇:多執行緒鎖
