Service.restart() 生成大量不需要的线程
Service.restart() generates an huge unwanted amount of threads
当用户在 TextField 中输入时:我需要通过 WebRequest 搜索一些数据并显示它们。
当用户输入多个字符时,应该取消之前的下载并开始新的下载。
所以我使用一个Task来下载数据和一个Service来在任务returns时显示数据。
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 发生时,我希望服务执行的操作是取消当前 运行 的任务并开始一个新任务...而不是每次都附加一个新任务。
我怎样才能做到这一点?
我无法重现你提到的延迟。
与documented一样,Service
使用"some default executor"执行由createTask
方法创建的Task
s。如果你想修改默认行为,你可以配置执行器,例如:
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
当用户在 TextField 中输入时:我需要通过 WebRequest 搜索一些数据并显示它们。
当用户输入多个字符时,应该取消之前的下载并开始新的下载。
所以我使用一个Task来下载数据和一个Service来在任务returns时显示数据。
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 发生时,我希望服务执行的操作是取消当前 运行 的任务并开始一个新任务...而不是每次都附加一个新任务。
我怎样才能做到这一点?
我无法重现你提到的延迟。
与documented一样,Service
使用"some default executor"执行由createTask
方法创建的Task
s。如果你想修改默认行为,你可以配置执行器,例如:
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