简体   繁体   English

试图在java中同时停止多个线程中的单个线程

[英]Trying to stop a single thread out of multiple running at the same time in java

So im trying to stop a single thread when I have multiple threads running, here is the code im using to initialise the threads.所以当我有多个线程运行时,我试图停止单个线程,这是我用来初始化线程的代码。 Basically I have multiple textFields in javafx, and when a button is clicked on the screen, it fills the textFields, one by one, with an incrementing timer.基本上我在 javafx 中有多个 textField,当在屏幕上单击一个按钮时,它会用递增的计时器一个一个地填充 textField。 Now I also have a button for each of the textfields to clear it, but the problem is when I clear it, because the thread is still running, the timer vanishes for a second and comes back because of the line 'orderTimes.get(boxNo).setText(minute + second);'现在我还有一个用于每个文本字段的按钮来清除它,但问题是当我清除它时,因为线程仍在运行,计时器会消失一秒钟并由于行 'orderTimes.get(boxNo ).setText(分+秒);' in the code.在代码中。

Now what I've tried is creating a list of threads and I've tried implementing it below but it doesn't work, this is so I can call each individual thread if its button to clear has been clicked.现在我尝试的是创建一个线程列表,我已经尝试在下面实现它,但它不起作用,这样我就可以在单击要清除的按钮时调用每个单独的线程。

Does anyone know how I can close/stop only one single thread out of multiple that are running?有谁知道我如何才能关闭/停止正在运行的多个线程中的一个? If more info is needed just let me know, thanks.如果需要更多信息,请告诉我,谢谢。

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

The code I'm using to clear the textfields is below, with orderTimes being the list of textFields that I'm trying to clear.我用来清除文本字段的代码如下,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();
}

I would suggest you try to avoid Threads .我建议你尽量避免Threads The Animation API is designed to make doing work that would normally be done in a Thread easier. Animation API 旨在使通常在Thread完成的工作变得更容易。 In this example, the IncrementingTimer class consists of two Labels and three Buttons .在此示例中, IncrementingTimer类由两个Labels和三个Buttons The Labels are used to show the time. Labels用于显示时间。 The Buttons are used to control the Timeline . Buttons用于控制Timeline The Timeline is used to increment the Labels value each second or every sixty seconds. Timeline用于每秒或每六十秒增加Labels值。 I have added three IncrementingTimers to the app.我在应用程序中添加了三个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().addAll(lblMinutes, lblColon, lblSeconds, btnPlay, btnStop, 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);
    }

}

As recommended and demonstrated by Sedric, use JavaFx Animation tools for the counters.按照 Sedric 的建议和演示,对计数器使用 JavaFx 动画工具。
The following one-file mre demonstrating implementation of counters using two different animation tools.以下单文件mre演示了使用两种不同动画工具实现计数器。
One uses PauseTransition and uses Timeline , each with its stop button.一种使用PauseTransition并使用Timeline ,每个都有其停止按钮。
(copy-paste the entire code into Timers.java and run) (将整个代码复制粘贴到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;
    }
}

The if(state=true) should rather be if(state==true) or just if(state) , but in fact the for(;;) could do the entire thing as while(state) , simply shutting down the thread when you set state=false . if(state=true)应该是if(state==true)或只是if(state) ,但实际上for(;;)可以像while(state)一样完成整个事情,只需在以下情况下关闭线程你设置state=false

Then, fully stopping the thread could happen as state=false;threadList.get(boxNo).join();然后,完全停止线程可能会发生state=false;threadList.get(boxNo).join(); , and you can clear the field only after that (since the thread will set it to something in the last step too). ,并且您只能在此之后清除该字段(因为线程也会在最后一步将其设置为某些内容)。


With a simpler approach you could throw away the state , and revert to for(;;) , with the twist of having the try-catch() around the loop, outside.使用更简单的方法,您可以丢弃state ,并恢复到for(;;) ,并在循环外使用try-catch()进行扭曲。 This way you can use threadList.get(boxNo).interrupt();threadList.get(boxNo);.join();这样你就可以使用threadList.get(boxNo).interrupt();threadList.get(boxNo);.join(); to stop the thread, and on top of that it will be immediate, as the sleep() ends immediately when the thread is interrupted.停止线程,最重要的是它将是立即的,因为当线程被中断时sleep()立即结束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM