试图在Java中同时运行的多个线程中停止单个线程

问题描述 投票:1回答:3

所以当我有多个线程在运行时,我试图停止一个线程,这是我用来初始化线程的代码。基本上,我在javafx中有多个textField,并且在屏幕上单击一个按钮时,它会使用递增计时器将textField逐一填充。现在我还为每个文本字段都有一个按钮来清除它,但是问题是当我清除它时,由于线程仍在运行,计时器消失了一秒钟,然后由于'orderTimes.get(boxNo ).setText(分钟+秒);'在代码中。

现在,我尝试创建一个线程列表,并尝试在下面实现它,但是它不起作用,因此,如果单击了要清除的按钮,则可以调用每个单独的线程。

有人知道我如何只能关闭/停止正在运行的多个线程中的一个?如果需要更多信息,请告诉我,谢谢。

public static void createIncrementingTimer(int boxNo, List<TextField> orderTimes) {
minutesList.set(boxNo, 0);
secondsList.set(boxNo, 0);
state = true;
new Thread(threadList.get(boxNo))  {
  int currentMinutes = 0;
  int currentSeconds = 0;
  public void run() {
    for (;;) {
      if (state = true) {
        try {
          sleep(1000);
          if (secondsList.get(boxNo) > 59) {
            secondsList.set(boxNo, 0);
            currentSeconds = 0;
            minutesList.set(boxNo, currentMinutes + 1);
            currentMinutes++;
          }            
          if (secondsList.get(boxNo) < 10) {
            second = ":0" + Integer.toString(secondsList.get(boxNo));
          } else {
            second = ":" + Integer.toString(secondsList.get(boxNo));                 
          }                            
          secondsList.set(boxNo, currentSeconds + 1);
          currentSeconds++;            
          if (minutesList.get(boxNo) < 10) {
            minute = "0" + Integer.toString(minutesList.get(boxNo));
          } else {
            minute = Integer.toString(minutesList.get(boxNo));
          }
          orderTimes.get(boxNo).setText(minute + second);             
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }
};
threadList.get(boxNo).start();
}

我用于清除文本字段的代码如下,orderTimes是我要清除的文本字段的列表。

public static void eraseBox(int clickedButtonNumber, List<TextArea> orderContentsList, List<TextField> tableNumbers, List<TextField> orderNumbers, List<TextField> orderTimes) {
orderContentsList.get(clickedButtonNumber).setText(null);
  tableNumbers.get(clickedButtonNumber).clear();
  orderNumbers.get(clickedButtonNumber).clear();
  orderTimes.get(clickedButtonNumber).clear();
}
java multithreading javafx textfield java-threads
3个回答
1
投票

我建议您尝试避免使用ThreadsAnimationAPI旨在简化通常在Thread中完成的工作。在此示例中,IncrementingTimer类包含两个Labels和三个ButtonsLabels用于显示时间。 Buttons用于控制TimelineTimeline用于每秒或每60秒增加Labels值。我已经在应用程序中添加了三个IncrementingTimers

Main

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {

    @Override
    public void start(Stage stage) {        
        var scene = new Scene(new VBox(new IncrementingTimer(), new IncrementingTimer(), new IncrementingTimer()), 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

IncrementingTimer

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.util.Duration;

/**
 *
 * @author blj0011
 */
final public class IncrementingTimer extends HBox
{
    IntegerProperty secondsCounter = new SimpleIntegerProperty();//Keeps up with seconds
    IntegerProperty minutesCounter = new SimpleIntegerProperty();//Keeps up with minutes

    Label lblSeconds = new Label();//Displays the seconds
    Label lblMinutes = new Label();//Displays the minutes
    Label lblColon = new Label(":");//Display the colon between minutes and seconds

    Button btnPlay = new Button("Play");//Plays the Timeline
    Button btnStop = new Button("Stop");//Stops the Timeline
    Button btnPause = new Button("Pause");//Pauses the Timeline

    Timeline timeline;//Used to run code that changes the Labels. This Timeline runs every one second.

    public IncrementingTimer()
    {
        lblSeconds.textProperty().bind(secondsCounter.asString("%02d"));//Binds the seconds label to the seconds counter. Sets the String to always show two digits. Exmaple 1 is shown as 01.
        lblMinutes.textProperty().bind(minutesCounter.asString("%02d"));//Binds the minutes label to the minutes counter. Sets the String to always show two digits. Exmaple 1 is shown as 01.

        getChildren().add(lblMinutes);
        getChildren().add(lblColon);
        getChildren().add(lblSeconds);
        getChildren().add(btnPlay);
        getChildren().add(btnStop);
        getChildren().add(btnPause);

        timeline = new Timeline(new KeyFrame(Duration.seconds(1), (event) -> {//Replace the one with .016 to speed this up for testing purposes.
            secondsCounter.set(secondsCounter.get() + 1);
            if (secondsCounter.get() == 60) {
                secondsCounter.set(0);
                minutesCounter.set(minutesCounter.get() + 1);
                if (minutesCounter.get() == 60) {
                    minutesCounter.set(0);
                }
            }
        }));
        timeline.setCycleCount(Timeline.INDEFINITE);
        btnPlay.setOnAction((event) -> {
            timeline.play();
        });
        btnPause.setOnAction((event) -> {
            timeline.pause();
        });
        btnStop.setOnAction((event) -> {
            timeline.stop();
            secondsCounter.set(0);
            minutesCounter.set(0);
        });

        this.setAlignment(Pos.CENTER);
    }

}

0
投票

if(state=true)应该是if(state==true)或仅仅是if(state),但实际上for(;;)可以像while(state)一样完成整个工作,只需在设置state=false时关闭线程即可。

然后,完全停止线程可能会发生state=false;threadList.get(boxNo).join();,并且您只能在此之后清除该字段(因为线程也将在最后一步将其设置为某些内容)。


[使用更简单的方法,您可以丢掉state,然后恢复为for(;;),但又需要在外部将try-catch()环绕在循环中。这样,您可以使用threadList.get(boxNo).interrupt();threadList.get(boxNo);.join();停止线程,并且它会立即终止,因为当线程中断时sleep()会立即终止。


0
投票

按照Sedric的建议and demonstrated,将JavaFx动画工具用于计数器。以下一个文件mre演示了使用两种不同的动画工具实现计数器的方法。一个使用PauseTransition,另一个使用Timeline,每个按钮都有其停止按钮。(将整个代码复制粘贴到Timers.java中并运行)

import java.io.IOException;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Timers extends Application {

    @Override public void start(final Stage stage) throws IOException {
        VBox root = new VBox(new CounterPane(new TimeLineCounter()), new CounterPane(new PauseTransitionCounter()));
        stage.setScene(new Scene(root));
        stage.show();
    }

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

class CounterPane extends HBox{

    private final Counter counter;
    CounterPane(Counter counter) {
        super(5);
        this.counter = counter; //todo: check not null
        Button stopBtn = new Button("Stop");
        stopBtn.setOnAction(e->stop());
        getChildren().addAll(stopBtn, counter);
    }

    void stop(){
        counter.getAnimation().stop();
    }
}

abstract class Counter extends Label {

    protected int count = 0;
    public Counter() {
        setAlignment(Pos.CENTER); setPrefSize(25, 25);
        count();
    }

    abstract void count();
    abstract Animation getAnimation();
}

class TimeLineCounter extends Counter {

    private Timeline timeline;

    @Override
    void count() {

        timeline = new Timeline();
        timeline.setCycleCount(Animation.INDEFINITE);
        final KeyFrame keyFrame = new KeyFrame(
                Duration.seconds(1),
                event -> {  setText(String.valueOf(count++) );  }
                );
        timeline.getKeyFrames().add(keyFrame);
        timeline.play();
    }

    @Override
    Animation getAnimation() {
        return timeline;
    }
}

class PauseTransitionCounter extends Counter {

    private PauseTransition pauseTransition;

    @Override
    void count() {

        pauseTransition = new PauseTransition(Duration.seconds(1));
        pauseTransition.setOnFinished(event ->{
            setText(String.valueOf(count++) );
            pauseTransition.play();
        });
        pauseTransition.play();
    }

    @Override
    Animation getAnimation() {
        return pauseTransition;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.