【问题标题】:Program doesn't stop after closing application关闭应用程序后程序不会停止
【发布时间】:2015-07-03 03:23:28
【问题描述】:

我尝试重新创建 Connect Four,并且成功了。但我想通过每隔一段时间切换颜色来让玩家知道获胜的四张光盘在哪里。我不熟悉线程和编程中的时间概念。

我也成功地给了用户这个指示,但是在我关闭应用程序后,控制台仍然给出输出,当我使用 setOnCloseRequest 时也是如此。

其他一些问题:
1:对于我使用 html 名称的颜色,是使用十六进制三元组更好还是不使用偏好。
2 : 为了阻止网格和其他元素紧贴屏幕左侧,我添加了一个与背景颜色相同的边框,有没有更好的方法?
3:我没有创建将键码转换为整数的方法,而是在 init 函数中创建。我这样做是因为我不知道如何传递 keyevent。如何做到这一点?

代码如下:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class FourInARow extends Application {

GridPane boardGrid = new GridPane();

Label[][] labels = new Label[7][7];
Label statusLabel = new Label();
int[][] cell = new int[7][6];

int player = 0;
int won = 0;

String baseStyle = "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: ";

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

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

private void init(Stage window){

    createLabels();
    startGame();

    Label above = new Label("Try to connect four discs in a row!");
    above.setStyle("-fx-font-size: 30; -fx-alignment: center; -fx-min-width: 600");
    boardGrid.setStyle("-fx-background-color: silver;-fx-border-color: #F4F4F4;-fx-border-width: 0 20 0 20");
    Button newGame = new Button("New Game");
    newGame.setStyle("-fx-min-width: 100;-fx-font-size:20");
    newGame.setOnAction(e -> startGame());
    statusLabel.setStyle("-fx-font-size: 30;-fx-alignment: center; -fx-min-width: 300;");
    HBox below = new HBox();
    below.setStyle("-fx-border-width: 0 0 0 20;-fx-border-color: #F4F4F4");
    below.getChildren().addAll(newGame, statusLabel);
    VBox layout = new VBox();
    layout.getChildren().addAll(above, boardGrid, below);
    Scene scene = new Scene(layout, 600, 620);
    scene.setOnKeyPressed(e -> {
        if (won == 0) {
            try {
                String k = e.getCode().toString();
                int l = k.length();
                int col = Integer.parseInt(k.substring(l - 1, l)) - 1;
                placeDisc(col, player);
                switchPlayer();
                updateScreen();
            } catch (NumberFormatException | ArrayIndexOutOfBoundsException error) {
                System.out.println("error: " + error);
            }
        }
    });
    window.setScene(scene);
    window.setTitle("Connect Four");

    threadThing();
}

private void threadThing() {
    service.scheduleAtFixedRate(() -> {
        try {
            wonStyle();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, 0, 1, TimeUnit.SECONDS);
}

private void startGame() {
    cell = new int[7][6];
    won = player = 0;
    statusLabel.setText("");
    updateScreen();
}

private void updateScreen() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            labels[i][j].setStyle(baseStyle + addStyle(cell[i][j]));
        }
        labels[i][6].setText(Integer.toString(i+1));
        labels[i][6].setStyle("-fx-alignment: center;-fx-min-width: 80;-fx-background-color: #F4F4F4;-fx-font-size: 30;");
    }

    switch(won) {
        case 1: statusLabel.setText("Blue has won!");break;
        case 2: statusLabel.setText("Yellow has won!");break;
    }
}

private String addStyle(int cell) {
    String style = "silver";
    switch(cell){
        case 1: style = "blue"; break;
        case 2: style = "yellow"; break;
        case 3: style = "darkblue"; break;
        case 4: style = "gold;"; break;
    }
    return style;
}

private void placeDisc(int col, int player) {
    for (int i = 5; i >= 0 ; i--) {
        if(cell[col][i] == 0){
            cell[col][i] = 1;
            if(player == 1) cell[col][i] = 2;
            break;
        }else{
            if(i==0) switchPlayer();
        }
    }
    checkWon();
}

private void checkWon() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if (cell[i][j] != 0) {
                try {
                    if (cell[i][j] == cell[i][j + 1] && cell[i][j] == cell[i][j + 2] && cell[i][j] == cell[i][j + 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i][j + 1] = cell[i][j + 2] = cell[i][j + 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell[i + 1][j] && cell[i][j] == cell[i + 2][j] && cell[i][j] == cell[i + 3][j]) {
                        System.out.println("Horizontal win");
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j] = cell[i + 2][j] = cell[i + 3][j] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell[i + 1][j + 1] && cell[i][j] == cell[i + 2][j + 2] && cell[i][j] == cell[i + 3][j + 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j + 1] = cell[i + 2][j + 2] = cell[i + 3][j + 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
                try {
                    if (cell[i][j] == cell [i + 1][j - 1] && cell[i][j] == cell[i + 2][j - 2] && cell[i][j] == cell[i + 3][j - 3]) {
                        won = cell[i][j];
                        cell[i][j] = cell[i + 1][j - 1] = cell[i + 2][j - 2] = cell[i + 3][j - 3] = cell[i][j] + 2;
                    }
                }catch(ArrayIndexOutOfBoundsException error) {}
            }
        }
    }
}

private void switchPlayer() {
    if(player == 0) player = 2;
    player--;
}

private void createLabels() {
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 7; j++) {
            labels[i][j] = new Label();
            boardGrid.add(labels[i][j], i, j);
        }
    }
}

private void wonStyle() throws InterruptedException {
    System.out.println("Test");
    boolean run = false;
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] > 2 && !run){
                Thread.sleep(500);
                addStyleFlicker();
                run = true;
            }
        }
    }
}

private void addStyleFlicker() throws InterruptedException {
    String[] styleOne = {"-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: blue;",
                         "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: darkblue;"};
    String[] styleTwo = {"-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: yellow;",
                         "-fx-background-radius: 40; -fx-min-width: 80; -fx-min-height: 80; -fx-alignment: center; -fx-border-width: 2; -fx-border-color: #000000;-fx-background-color: gold;"};
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] == 3){
                labels[i][j].setStyle(styleOne[0]);
            }else if(cell[i][j] == 4){
                labels[i][j].setStyle(styleTwo[0]);
            }
        }
    }
    Thread.sleep(500);
    for (int i = 0; i < 7; i++) {
        for (int j = 0; j < 6; j++) {
            if(cell[i][j] == 3){
                labels[i][j].setStyle(styleOne[1]);
            }else if(cell[i][j] == 4) {
                labels[i][j].setStyle(styleTwo[1]);
            }
        }
    }
}

@Override
public void start(Stage window) throws Exception {
    init(window);
    window.show();
}
}

【问题讨论】:

  • 我已经查看了该帖子,但没有找到解决方案。
  • 使用创建守护线程的线程工厂创建执行器。 (如果在我回到我的电脑之前没有其他人这样做,将发布一个带有代码的答案。)
  • 我怀疑你需要关闭你的执行程序,并确保你的 Runnable 实现在引发/抛出 InterruptedException 时重置中断标志
  • stackoverflow.com/a/31519051/3796962 -- 请找到此链接,它可能对您有所帮助。谢谢..

标签: java multithreading events javafx


【解决方案1】:

根据 Thread 类的 Java API 文档...

Java 虚拟机继续执行线程,直到发生以下任一情况:

  • 已调用 Runtime 类的退出方法,并且安全管理器已允许执行退出操作。
  • 不是守护线程的所有线程都已死亡,要么从调用 run 方法返回,要么抛出传播到 run 方法之外的异常。

因此,您需要该 Executor 创建 Daemon 线程,这些线程将在 JVM 准备退出时终止。您可以使用自定义线程工厂来执行此操作。这是一个非常简单的例子:

Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
        
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    });

【讨论】:

  • 这也有效,谢谢大卫,两个答案中的一个比另一个更好吗?还是更适合这种情况?
  • 我认为它们都是有效的,但是 System.exit(0) IMO 是对真正原因的创可贴,即非守护线程阻止 JVM 退出。无论如何,最好了解守护线程,这样您就可以在调用 System.exit 可能不是一个好主意的情况下使用它们,例如第三方可能依赖的 Web 应用程序或库。
  • @RichardKoetchruyter 必须同意大卫的观点。这个答案鼓励更好的做法。由于另一个线程仍处于活动状态,您的应用程序仍在运行。将该线程设置为daemon 可确保VM 仍然可以退出,即使该线程可能仍在运行。 System.exit 更像是一个便宜的修复程序,基本上是说“我不知道是什么让我的虚拟机保持运行,所以退出一切”。该答案指出“此线程不会导致 VM 继续运行”
  • 调用Runtime、getRuntime().exit(0)和System.exit(0)有什么区别?前者更好吗?
  • 据我所知,System.exit() 调用了 Runtime.getRuntime().exit(),所以没关系。还有一个 Runtime.getRuntime().halt() 选项,它更类似于强制杀死(想想终端上的kill -9)。它不会运行终结器,不会关闭资源,也不会运行关闭挂钩。
【解决方案2】:

Application 类覆盖stop() 方法将允许您关闭控制台应用程序:

@Override
public void stop() {
    System.exit(0);
}

【讨论】:

  • 谢谢,成功了:)
  • 我猜 kill -9 也可以,但我强烈建议坚持优雅地浸泡所有线程。
猜你喜欢
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 2018-07-17
  • 1970-01-01
相关资源
最近更新 更多