2015-11-03 38 views
0

當用戶輸入TextField時:我需要通過WebRequest搜索一些數據並顯示它們。Service.restart()生成大量不需要的線程數

當用戶輸入多個字符時,應取消上一次下載,並開始新的下載。

所以我使用一個任務下載數據和一個服務來顯示數據,當任務返回它們時。

s = new Service(){ 
    @Override 
    protected Task createTask() { 
     return new Task<String>(){ 
      @Override 
      protected String call() throws Exception { 
       //DOWNLOAD DATA 
       System.out.println("1"); 
       Thread.sleep(1000); 
       System.out.println("2"); 
       Thread.sleep(1000); 
       System.out.println("3"); 
       Thread.sleep(1000); 
       return "banana"; 
      } 
     }; 
    } 
}; 
s.setOnSucceeded(new EventHandler<WorkerStateEvent>(){ 
    @Override 
    public void handle(WorkerStateEvent event) { 
     System.out.println(event.getSource().getValue() + " DISPLAYED"); 
    } 
}); 

//HANDLE KEY RELEASED ON A TEXTFIELD 
public void onTextFieldKeyReleased() { 
    s.restart(); 
} 

我注意到,每次服務重新啓動時,都會出現另一個線程,直到出現一定數量的線程。 這使程序顯示數據的時間很長。

當KeyReleasedEvent發生時,我希望服務執行的操作是取消當前正在運行的任務並開始一個新任務...每次新任務時都不會追加任務。

我該如何做到這一點?

+0

我無法重現「巨大的延遲「與您發佈的代碼。你可以創建一個[MCVE]嗎? –

+0

@James_D也許你不能重現延遲,但你可以看到有很多線程被創建,我不希望這樣的情況發生。 另外,我注意到在打印每個線程之前,生成的服務必須關閉,這需要一秒鐘,對我來說太多了。 – user2468425

+0

我不明白爲什麼創建新線程會導致問題,但是您是否閱讀了[documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Service.html #setExecutor-java.util.concurrent.Executor-)? 「打印生成的服務產生的每個線程必須關閉之前」是什麼意思?我不明白這一點。你至少能用代碼來編輯你的問題,即使你不會發布代碼來證明延遲? –

回答

0

我無法重現您提到的延遲。

由於documentedService使用「某些默認執行程序」來執行由createTask方法創建的Task。您可以配置執行,如果你想修改默認的行爲,例如:

s.setExecutor(Executors.newCachedThreadPool(runnable -> { 
    Thread t = new Thread(runnable); 
    t.setDaemon(true); 
    return t ; 
}); 

很明顯,你可以請根據您的具體要求(這並不完全清楚你的問題),你選擇的任何遺囑執行人。例如,如果你想限制(說)5線程,你可以做

s.setExecutor(Executors.newFixedThreadPool(5, runnable -> { 
    Thread t = new Thread(runnable); 
    t.setDaemon(true); 
    return t ; 
}); 

這是一個SSCCE。我加了一些記錄到跟蹤服務的狀態,並顯示該線程正在使用的任務:

import java.util.concurrent.Executors; 

import javafx.application.Application; 
import javafx.concurrent.Service; 
import javafx.concurrent.Task; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class ServiceRestartTest extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Service<Void> s = new Service<Void>(){ 
      @Override 
      protected Task<Void> createTask() { 
       return new Task<Void>(){ 
        @Override 
        protected Void call() throws Exception { 
         //DOWNLOAD DATA 
         System.out.println("New task on thread "+Thread.currentThread()); 
         System.out.println("1"); 
         Thread.sleep(1000); 
         System.out.println("2"); 
         Thread.sleep(1000); 
         System.out.println("3"); 
         Thread.sleep(1000); 
         return null; 
        } 
       }; 
      } 
     }; 
     s.setExecutor(Executors.newCachedThreadPool(runnable -> { 
      Thread t = new Thread(runnable); 
      t.setDaemon(true); 
      return t; 
     })); 

     s.stateProperty().addListener((obs, oldState, newState) -> System.out.println(newState)); 

     TextField textField = new TextField(); 
     textField.setOnKeyReleased(e -> s.restart()); 

     primaryStage.setScene(new Scene(new StackPane(textField), 350, 120)); 
     primaryStage.show(); 

    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

輸出,只顯示兩個線程使用:

 
SCHEDULED 
New task on thread Thread[Thread-5,5,main] 
1 
RUNNING 
CANCELLED 
READY 
SCHEDULED 
New task on thread Thread[Thread-6,5,main] 
1 
RUNNING 
CANCELLED 
READY 
SCHEDULED 
New task on thread Thread[Thread-6,5,main] 
1 
RUNNING 
CANCELLED 
READY 
SCHEDULED 
New task on thread Thread[Thread-6,5,main] 
1 
RUNNING 
CANCELLED 
READY 
SCHEDULED 
New task on thread Thread[Thread-6,5,main] 
1 
RUNNING 
CANCELLED 
READY 
SCHEDULED 
New task on thread Thread[Thread-6,5,main] 
1 
RUNNING 
2 
3 
SUCCEEDED 
+0

似乎將執行程序設置爲Executors.newSingleThreadScheduledExecutor()解決了太多線程問題 – user2468425

+0

我試過了您的版本,但它在我的情況下不起作用,無論如何謝謝您幫助我做事情正確的方式。如果你編輯你的答案,我會投票。 – user2468425

+1

你大概不需要一個安排的執行者(在你的調度問題中至少沒有任何問題)。如果你真的需要兩件事情異步發生,單線程執行程序會導致問題。緩存的線程池重用線程:我只看到兩個線程在這裏創建。 –