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方法创建的Tasks。如果你想修改默认行为,你可以配置执行器,例如:

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