任务挂起

问题描述:

当我通过IntelliJ运行应用程序(最新版本)时,我的最后一项任务是永久挂起。 其实我试图调试,它挂在fetchRegisterCourseList()。 我可以看到它挂起,因为我有一个进度指示器,并且从未获取特定数据。另一方面,当我将我的应用程序打包到jar并正常执行时,它永远不会挂起,一切正常。任务挂起

这是一个IntelliJ或代码相关的错误?

AuthController:

 ... // previous tasks 

     Task<List<Course>> parseGradesTask = new Task<List<Course>>() { 
      @Override 
      public List<Course> call() { 
       return studentParser.parseStudentGrades(); 
      } 
     }; 

     Task<HashMap<String, String>> parseRegTask = new Task<HashMap<String, String>>() { 
      @Override 
      public HashMap<String, String> call() { 
       return studentParser.parseStudentRegistration(); 
      } 
     }; 

     parseGradesTask.setOnSucceeded(e -> { 
      serializeService.serializeCourses(parseGradesTask.getValue()); 
      progressIndicator.setProgress(0.6); 
     }); 

     parseRegTask.setOnSucceeded(e -> { 
      // it is hanging at this line: 
      List<Course> regList = serializeService.fetchRegisterCourseList(parseGradesTask.getValue(), parseRegTask.getValue()); 
      serializeService.serializeRegister(regList); 
      updateMainComponents(); 
     }); 

     ExecutorService es = Executors.newSingleThreadExecutor(); 
     es.submit(parseInfoTask); 
     es.submit(parseGradesTask); 
     es.submit(parseStatsTask); 
     es.submit(parseRegTask); 
     es.shutdown(); 

private void updateMainComponents() { 
    MainController.getInstance().updateAllViewComponents(); 

    if (preferenceService.getPreferences().getPrefSyncEnabled()) { 
     SyncScheduler.getInstance().stopScheduler(); 
     SyncScheduler.getInstance().startSyncScheduler(preferenceService.getPreferences().getPrefSyncTime()); 
    } 
    dialogStage.close(); //close this window 
} 

serializeService:

public List<Course> fetchRegisterCourseList(List<Course> courseList, HashMap<String, String> courseIdList) { 
    List<Course> courseRegList = new ArrayList<>(); 

    Iterator it = courseIdList.entrySet().iterator(); 
    while (it.hasNext()) { 
     Map.Entry pair = (Map.Entry) it.next(); 
     courseRegList.addAll(courseList.stream().filter(course -> 
       course.getCourseId().equals(pair.getKey()) && course.getCourseTitle().equals(pair.getValue())) 
       .collect(Collectors.toList())); 
     it.remove(); // avoids a ConcurrentModificationException 
    } 
    return courseRegList; 
} 
+0

IDK什么所有这些语句都在做,但昂贵的任务应该在'Task's的'call'方法来完成。我没有看到你从'onSucceeded'处理器得到任何结果,这看起来更奇怪。从方法名中猜测'updateMainComponents();'应该是'parseRegTask'的'onSucceeded'处理程序中唯一执行的。 – f*

+0

谢谢f*。这似乎解决了我的问题。如果你愿意的话,你可以把它写成关闭这个问题的答案。虽然我很想知道为什么会发生(甚至假设)。 – pror21

+0

绝对不是IntelliJ的错误。首先,最后,永远怀疑自己。 – duffymo

onSuceeded处理程序被调用在JavaFX应用程序THEAD。这里不应该进行长时间运行的操作。最好只在这里做UI更新。 Task的结果可用于“发布”操作的结果。该值可以在onSucceeded处理程序中检索。

在您的代码中,您正在onSucceeded处理程序中运行这些操作,这会阻止UI线程。

下面的示例演示如何使用Task正确:

@Override 
public void start(Stage primaryStage) { 
    TextArea textArea = new TextArea(); 
    Button button = new Button("Get Text"); 
    button.setOnAction(evt -> { 
     button.setDisable(true); 
     Task<String> task = new Task<String>() { 

      @Override 
      protected String call() throws Exception { 
       // do long-running operations not modifying the UI 
       // here 
       StringBuilder sb = new StringBuilder(); 

       final int count = 10; 

       for (int i = 0; i < count; i++) { 
        // update message & progress 
        // the messageProperty/progressProperty will be modified on 
        // the javafx application thread 
        updateProgress(i, count); 
        updateMessage("Loading part " + (i+1)); 

        // simulate long-running operation 
        Thread.sleep(500); 
        sb.append('\n').append(i); 
       } 
       updateProgress(count, count); 
       return sb.toString(); 
      } 

     }; 

     // while loading, display the task message in the TextArea 
     textArea.textProperty().bind(task.messageProperty()); 

     task.setOnSucceeded(succeededEvent -> { 
      // only modifications of the UI here, no longrunning tasks 
      textArea.textProperty().unbind(); 

      // use result of the task 
      textArea.setText(task.getValue()); 

      button.setDisable(false); 
     }); 

     // run task on different thread 
     new Thread(task).start(); 
    }); 

    Scene scene = new Scene(new VBox(textArea, button)); 

    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 
+0

可以updateProgress和updateMessage()内使用call()?我想从命名这些方法正在改变属性到主要的JavaFX线程。 – pror21

+0

@ pror21我在调用方法中使用了这些方法,不是吗?那些确实可以从这个方法调用,即使它运行在不同的线程上,请参阅https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html#updateProgress-long-long-和https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html#updateMessage-java.lang.String- – f*

+0

ahh我不知道这些方法是任务类的一部分。有趣!再次感谢 – pror21