任务取消方法或事件

时间:2018-01-14 20:55:46

标签: java networking javafx concurrency

我正在尝试创建一个网络javafx应用程序并在任务中运行serverloop。因为ServerSocket接受方法是阻塞的,并且我无法测试任务是否被取消(使用isCancelled())。

我当前的实施:

class ServerTask extends Task<Void> {
    ExecutorService executorService;
    final int PORT = 12345;

    @Override
    protected Void call() throws Exception {
        executorService = Executors.newFixedThreadPool(8);

        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            while (true)
            {
                executorService.execute(
                        new Client(serverSocket.accept()));
            }
        }
        catch (IOException e) {
            System.out.print(e.getMessage());
        }

        return null;
    }
}

当在某个任务上调用chancel或者我在javafx应用程序中实现serverloop的方法错误时,是否有可能覆盖或捕获事件?如果是这样,应该怎么做?

1 个答案:

答案 0 :(得分:1)

一旦Task被调用,CANCELLED就会转换为cancel()状态,即使call()方法仍然被阻止运行不间断方法。

通过关闭套接字可以有效地“中断”ServerSocket,这将导致当前被阻止的任何accept()方法以IOException终止。

所以你可以这样做:

class ServerTask extends Task<Void> {
    ExecutorService executorService;
    final int PORT = 12345;

    private ServerSocket serverSocket ;

    @Override
    protected Void call() throws Exception {
        executorService = Executors.newFixedThreadPool(8);

        try (serverSocket = new ServerSocket(PORT)) {
            while (true)
            {
                executorService.execute(
                        new Client(serverSocket.accept()));
            }
        }
        catch (IOException e) {
            if (isCancelled()) {
                System.out.println("Cancelled");
            } else {
                System.out.print(e.getMessage());
            }
        }

        return null;
    }

    @Override
    protected void cancelled() {
        if (serverSocket != null) {
            try {
                serverSocket.close();
            } catch (IOException exc) {
                exc.printStackTrace();
            }
        }
    }
}

这是一个非常快速的完整示例:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class NonIterruptableTaskCancellation extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        ServerSocket socket = new ServerSocket(2048);

        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {

                while (! isCancelled()) {
                    try {
                        Socket s = socket.accept();
                        System.out.println("Connected to "+s);
                        s.close();
                    } catch (IOException exc) {
                        if (isCancelled()) {
                            System.out.println("Cancelled");
                        } else {
                            System.out.println("Unexpected IO Exception");
                            throw exc ;
                        }
                    }
                }

                return null ;
            }

            @Override
            protected void cancelled() {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread t = new Thread(task);
        t.setDaemon(true);
        t.start();

        Label label = new Label();
        label.textProperty().bind(task.stateProperty().asString());

        Button cancel = new Button("Cancel");
        cancel.disableProperty().bind(task.runningProperty().not());
        cancel.setOnAction(e -> task.cancel());

        VBox root = new VBox(5, label, cancel);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 200, 120);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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