Service.restart()会生成大量不需要的线程

时间:2015-11-03 20:45:18

标签: java multithreading javafx task java.util.concurrent

当用户输入TextField时:我需要通过WebRequest搜索一些数据并显示它们。

当用户键入多个字符时,应取消先前的下载并开始新的下载。

因此,当任务返回时,我使用Task下载数据和Service来显示数据。

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();
}

我注意到每次重新启动Service时都会出现另一个Thread,直到有一定数量的线程。 这使得程序显示数据有很大的延迟。

当KeyReleasedEvent发生时,我希望服务做的是取消当前正在运行的任务并启动一个新任务...每次新任务都不附加。

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:0)

我无法再现你提到的延迟。

作为documentedService使用“some default executor”来执行Task方法创建的createTask。如果要修改默认行为,可以配置执行程序,例如:

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