Java FX如何'Stop'线程中途并重新启动或销毁它

Java FX How to 'Stop' Thread Midway and Restart it or destroy it

无法停止线程中途重新启动添加节点线程。

这就是我得到的

这就是我需要的每当我按下刷新按钮[=时,我都想要这样的东西74=]

clean screen and Restart(例如。A 到 N 按正确顺序排列)

为什么?所以我可以在刷新前选择不同的列表。

背景故事 (忽略) 一个月以来,我一直在做一个关于 JavaFX 的小项目,但这个问题一直困扰着我。我做了我的研究并试图弄清楚但没有。如果有人在正确的道路上引导我,我真的很感激。请高亮这个问题,这样其他人就不用浪费那么多时间了

我有 JavaFX 控制器

@FXML public FlowPane flow_panel;

MyPlatform mp = new MyPlatform(); // A class that implements Runnable
Thread t;

boolean first_time_click = true; // To check Whether i clicked '1st' time or 'second' time
@FXML
private void Refresh_Btn(ActionEvent event) 
{       
    System.out.println("Refresh btn");

     t = new Thread(mp); //Creating Thread object

    if(first_time_click == true) { first_time_click = false;



        MyPlatform.stop = false; //Thread object.Stop, When false do nothing

        flow_panel.getChildren().clear(); // cleaning screen
        System.out.println("Start Thread");
        t.setDaemon(true);  
        t.start(); //Start Thread


    } else if(first_time_click == false){   first_time_click = true;



        MyPlatform.stop = true; //Exist loop
        t.interrupt(); // I thought   't.interrupt()'   it work but nothing
        System.out.println("Stop Thread");

        flow_panel.getChildren().clear(); // cleaning screen
        MyPlatform.stop = false; //Thread object.Stop, When false do nothing
        t.setDaemon(true);
        t.start(); //Start Thread
        System.out.println("Stoped  Thread Started again");


    } 

}

然后我有一个名为 MyPlatform 的 class 实现了 Runnable

import javafx.application.Platform;
import javafx.scene.control.Button;
import setups.WindowSetupConfig;

public class MyPlatform implements Runnable
{   

public static boolean stop = false;

@Override
public void run()
{



    for (String name : ListOfNames.getlist()) 
    {
        if(stop)    // Exit for loop if true
        {
            break;
        }
        Platform.runLater(new Runnable()
        {

            @Override
            public void run()
            {   

                Button btn = new Button("Button : "+name);

                System.out.println(name);


        //Adding that button to FlowPane
        WindowSetupConfig.getController().flow_panel.getChildren().add(btn);
                }
            });

            try {
                Thread.sleep(1000); // Wait for 1 sec, Controlling speed
            } catch (InterruptedException e) { // try catch it needed for some reason
                e.printStackTrace();
            }

        }


    }

}

我有一个字符串列表。最初该列表将包含 500 多个名称

import java.util.ArrayList;

public class ListOfNames
{   
    private static ArrayList<String> list_of_names ;

    public ListOfNames()
    {
        list_of_names = new ArrayList<>();
        list_of_names.add("A");
        list_of_names.add("B");
        list_of_names.add("C");
        list_of_names.add("D");
        list_of_names.add("E");
        list_of_names.add("F");
        list_of_names.add("G");
        list_of_names.add("H");
        list_of_names.add("I");
        list_of_names.add("J");
        list_of_names.add("K");
        list_of_names.add("L");
        list_of_names.add("M");
        list_of_names.add("N");
    }


    public static ArrayList<String> getlist() {
        return list_of_names;
    }
}

每当我 按下 刷新按钮 我想停止线程 中途 添加点头流量面板。

使用 flow_panel.getChildren().clear(); 清理 FlowPane 并从列表的开头重新开始

基本上 -停止 -清洁 -重启

如果有任何方法可以使用 Servicetask 来完成,那就太好了

我找到了解决问题的方法。现在我的问题是有没有更好的方法来达到相同的结果 因为我正在和黄色交战,这意味着我做错了

Luncher.java

    package project;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Luncher extends Application
{


    @Override
    public void start(Stage primaryStage) {
        try {


            Parent root = FXMLLoader.load(getClass().getResource("Window.fxml"));

            Scene scene = new Scene(root);          

            primaryStage.setScene(scene);
            primaryStage.show();

        } catch(Exception e) {
            System.err.println("Luncher Failed !" +e);
        }
    }

    public static void main(String[] args) 
    {

        launch(args);

    }

}

Controller.java

package project;


import java.net.URL;
import java.util.ResourceBundle;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.FlowPane;


public class Controller implements Initializable
{


    @FXML
    public FlowPane flowPane;


    //A class that implements  Runable, So i can start a thead there
    private MyRunableClass my_run_class; 
    private Thread t; //Thread object

    @Override
    public void initialize(URL location, ResourceBundle resources)
    {       
        new ListOfNames(); //Init list of names and creating Array list, In real program i will get this list from database
        my_run_class = new MyRunableClass(this);

    }





    @FXML
    void clear_Button(ActionEvent event) 
    {
        flowPane.getChildren().clear(); 
    }


    @FXML
    void start_Button(ActionEvent event) 
    {   
        t = new Thread(my_run_class);
        t.start();
    }

    @FXML
    void stop_Button(ActionEvent event) {
        t.suspend(); ///NOT WORKING???????? any way to stop running thread
    }




    private boolean firstTime_thread_running = true; // To check Whether i clicked '1st' time or 'second' time

    @FXML
    void refresh_Button(ActionEvent event) 
    {


        if(firstTime_thread_running == false){


            //Stop
            //  my_run_class.stop = true; //Exist loop
            t.suspend();
            System.out.println("Suspend");

        } else
        {   
            firstTime_thread_running = false;
        }



//Clean
            flowPane.getChildren().clear(); // cleaning screen
            System.out.println("Screen clear");


//Restart , well.. at least that what i want
            t = new Thread(my_run_class);
            t.setDaemon(true);
            t.start(); //Start Thread
            System.out.println("Stoped  Thread Started again"); 

    }



}

MyRunableClass.java

    package project;

import javafx.application.Platform;
import javafx.scene.control.Button;

public class MyRunableClass implements Runnable
{       
    private Controller controller;

    public MyRunableClass(Controller controller)
    {   
        //Getting FXML Controller
        this.controller = controller;
    }

//  public boolean stop = false;

    @Override
    public void run()
    {



        for (String name : ListOfNames.getlist()) 
        {
//          if(stop)    // Exit for loop if true
//          {
//              break;
//          }
            Platform.runLater(new Runnable()
            {

                @Override
                public void run()
                {   

                    Button btn = new Button("Button : "+name);

                    System.out.println(name);

                    controller.flowPane.getChildren().add(btn);
                }
            });

            try {
                Thread.sleep(1); // Wait for half sec this time
            } catch (InterruptedException e) { // try catch it needed for some reason
                e.printStackTrace();
            }

        }


    }

}

ListOfNames.java

    package project;

import java.util.ArrayList;

public class ListOfNames
{   
    private static ArrayList<String> list_of_names ;

    public ListOfNames()
    {
        list_of_names = new ArrayList<>();
        list_of_names.add("A");
        list_of_names.add("B");
        list_of_names.add("C");
        list_of_names.add("D");
        list_of_names.add("E");
        list_of_names.add("F");
        list_of_names.add("G");
        list_of_names.add("H");
        list_of_names.add("I");
        list_of_names.add("J");
        list_of_names.add("K");
        list_of_names.add("L");
        list_of_names.add("M");
        list_of_names.add("N");
        list_of_names.add("O");
        list_of_names.add("P");
        list_of_names.add("Q");
        list_of_names.add("R");
        list_of_names.add("S");
        list_of_names.add("T");
        list_of_names.add("U");
        list_of_names.add("V");
        list_of_names.add("W");
        list_of_names.add("X");
        list_of_names.add("Y");
        list_of_names.add("Z");

    }


    public static ArrayList<String> getlist() {
        return list_of_names;
    }
}

Window.fxml

    <?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="413.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="project.Controller">
   <children>
      <FlowPane fx:id="flowPane" layoutX="2.0" layoutY="61.0" prefHeight="352.0" prefWidth="600.0" style="-fx-border-color: #000000; -fx-border-insets: 1.1; -fx-border-width: 5;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="61.0" />
      <Button layoutX="405.0" layoutY="14.0" mnemonicParsing="false" onAction="#stop_Button" prefHeight="39.0" prefWidth="80.0" text="Stop" />
      <Button layoutX="313.0" layoutY="14.0" mnemonicParsing="false" onAction="#start_Button" prefHeight="39.0" prefWidth="80.0" text="Star" />
      <Button layoutX="497.0" layoutY="14.0" mnemonicParsing="false" onAction="#clear_Button" prefHeight="39.0" prefWidth="80.0" text="Clean" />
      <Button layoutX="40.0" layoutY="14.0" mnemonicParsing="false" onAction="#refresh_Button" prefHeight="39.0" prefWidth="109.0" text="Refresh" />
   </children>
</AnchorPane>

我没有阅读您的所有代码,但我将对如何取消和 "restart" 和 Task 进行一般性说明。

首先,不要使用Threadsuspendstopresume方法;他们被弃用是有原因的。

与所有后台任务一样,取消需要该后台任务的开发人员的合作。该任务必须在适当的时候检查它是否已被取消并做出相应的反应。一般是通过查询当前Thread的中断状态来实现的,但是Taskclass继承了FutureTask更容易使用的isCancelled方法。

模拟长运行工作的例子:

public class MyTask extends Task<Void> {

    @Override
    protected Void call() throws Exception {
        for (int i = 0; i < 10_000; i++) {
            if (isCancelled()) {
                break;
            }
            updateMessage(Integer.toString(i));
            Thread.sleep(1L);
            updateProgress(i, 10_000);
        }
        return null;
    }

}

您使用 Worker 接口的 cancel 方法取消了 Task。注意在循环的每次迭代中检查 isCancelled;当调用 cancel 方法时,Task 将尽早停止。此外,调用 Worker.cancel()(或 Future.cancel(true))将中断 Thread,这意味着任何可中断的操作(例如 Thread.sleep)将抛出 InterruptedException

您可以通过观察 Task 的属性或添加事件处理程序来对 Task 成功、失败或取消做出反应。

MyTask task = new MyTask();
task.setOnSucceeded(event -> handleSucceededTask());
task.setOnFailed(event -> handleFailedTask());
task.setOnCancelled(event -> handleCancelledTask());

您可以在这些回调中进行清理并根据需要执行 new Task。请注意,您必须启动一个新的 Task,因为 Task 是一次性的。