Java 关闭线程';使用Runtime.exec()后的GUI

Java 关闭线程';使用Runtime.exec()后的GUI,java,process,libgdx,Java,Process,Libgdx,我正在用LibGDX制作一个游戏,现在我正试图通过重新运行jar来重新启动游戏,因为我正在使用jar的路径,使用: String location = new File(DesktopLauncher.class .getProtectionDomain().getCodeSource().getLocation() .getPath()).toString().replace("%20", " "); 使用之后,

我正在用LibGDX制作一个游戏,现在我正试图通过重新运行jar来重新启动游戏,因为我正在使用jar的路径,使用:

String location = new File(DesktopLauncher.class
                    .getProtectionDomain().getCodeSource().getLocation()
                    .getPath()).toString().replace("%20", " ");
使用之后,我尝试使用
进程和
Runtime.getRuntime().exec(“java-jar”+location+“\\Test.jar”)
到目前为止,它还可以工作,但问题是我创建新实例(从中重新启动)的游戏的第一个实例仍在屏幕上,直到第二个实例关闭后才会关闭。
这是我重新启动的代码:

public static void restart() {
    Gdx.app.exit();
    try {
        String location = new File(DesktopLauncher.class
                .getProtectionDomain().getCodeSource().getLocation()
                .getPath()).toString().replace("%20", " ");
        System.out.println(location);
        Process pro = Runtime.getRuntime().exec(
                "java -jar " + location + "\\Test.jar");
        BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
                "reprot.txt")));
        InputStream stream = pro.getErrorStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                stream));
        String line = "";
        writer.write(location);
        while ((line = reader.readLine()) != null) {
            writer.write(line);
        }
        writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
我做错什么了吗?启动第二个实例后,如何关闭游戏的第一个实例?
我尝试使用另一个线程执行此操作,代码如下:

    public static void main(String[] args) {
    try {

        String location = new File(DesktopLauncher.class
                .getProtectionDomain().getCodeSource().getLocation()
                .getPath()).toString();
        System.out.println(location);
        Process pro = Runtime.getRuntime().exec(
                "java -jar " + location + "\\Test.jar");
        BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
                "report.txt")));
        InputStream stream = pro.getErrorStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                stream));
        String line = "";
        writer.write(location);
        while ((line = reader.readLine()) != null) {
            writer.write(line);
        }
        writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
但它仍然存在同样的问题

编辑:我尝试使用
System.exit(0),并尝试使用LwjglApplication关闭它,但它保持不变,但我取得了一些进展:
创建这个新流程时,游戏的第二个实例,第一个实例的UI冻结,导致游戏没有响应。我想,如果它没有响应,我应该找到一种方法将其杀掉,并留下另一个实例,但这无法实现,因为当关闭游戏的一个实例时(通过强制关闭),您将关闭两个实例。
我想我找到了这个恼人的难题的一部分:
假设游戏的主要实例名为“game_1”,我们正在创建的实例名为“game_2”。
在看了代码并思考了会发生什么(通过测试小型类而不是大型游戏),我认为“游戏1”没有结束,因为“游戏2”没有结束。
在更复杂的术语中,“Game_1”的实例不会关闭,因为它以某种方式连接到“Game_2”,因此在“Game_2”关闭之前等待它关闭。
因此,如果这是正确的,关闭“Game_1”的方法是使“Game_2”与“Game_1”同时运行,使其独立,从而允许“Game_1”继续当前的代码进度,这将是
Gdx.app.exit()的实现方法。
所以现在的问题仍然是,如何使“Game_2”的实例独立于“Game_1”运行?或者,我如何让“游戏1”继续代码,或者不等待从“游戏2”收到退出值。
EDIT2:添加一行代码
系统后的大规模进展。退出(0)
在重新启动类中,“Game_1”继续没有响应,但在终止“Game_1”后,“Game_2”没有关闭,我将继续使用它,直到我知道该怎么做。
EDIT3:我继续尝试修复它,使其正常工作,但遇到了另一个问题。我发现,如果我可以模拟“Game_2”进程的退出值而不实际退出,我可以终止“Game_1”的UI,同时保持Game 2的活动状态,如果有人有任何想法,请与我分享
EDIT4:我继续尝试这样做,但我无法了解发生了什么,我试图通过编写
“java-cp”+location+“\\Test.jar Restart”+PID
但它似乎不起作用,或者我似乎没有从Restart类收到任何信息(例如syso)。除此之外,我在游戏中发现了一个内存泄漏问题,一旦我解决了这个问题,我将解决这个问题。
请,如果你有任何想法可以帮助我,哪怕只是一个理论,请分享。
EDIT5:我已经用这个




这是解决方案,因为我要到明天才能回答我的问题:

好的,最后,我解决了它,它有几个问题,我只会提到其中两个,因为它涉及到一般的代码,而不是我如何使用它Game_1'将是首先启动的游戏,Game_2'将是重新启动的游戏的实例。就是这样:
首先,我得到了当前正在运行的进程的PID,“Game_1”,我将从中创建“Game_2”。这方面的问题是Java应用程序都有相同的名称“Java.exe”,这导致了一堆同名的应用程序,所以现在我添加了一条消息,说游戏应该是计算机上唯一的Java实例,而不是eclipse或类似的东西。
PID检索的代码如下:

private static String getPID() {
    try {
        String line;
        Process p = Runtime.getRuntime().exec(
                System.getenv("windir") + "\\system32\\" + "tasklist.exe");
        BufferedReader input = new BufferedReader(new InputStreamReader(
                p.getInputStream()));
        while ((line = input.readLine()) != null) {
            System.out.println(line);
            if (line.contains("java")) {
                String data = line.subSequence(27, 35).toString();
                data = data.trim();
                return data;
            }
        }
        input.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "-1";
}
现在,稍后,我将寻找一种方法来命名当前正在运行的进程,这样您就不必使用
line.contains(“java”)
,因为它可能会给出多个实例,但目前它已经很好了。
此代码在windows中使用一个exe文件,该文件基本上提供了计算机上运行的所有当前进程,因此您可以找到您的程序。
返回的列表以以下格式给出:

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
All the processes will be located here.
C:\A%20Folder\To%20YourJar\YourJar.jar
PID位于第27个字符到第35个字符之间,这就是我添加
String data=line.subSequence(27,35).toString()
从而返回进程的PID。
这样做之后,我准备了一个带有执行命令的cmd,如下所示:

String jarLocation = new File(YourClass.class.getProtectedDomain().getCodeSource().getLocation().getPath()).toString();
String command = "java -cp " + jarLocation + " your.Package.here.Restart \""+PID+"\"";
Runtime.getRuntime().exec("cmd /C start cmd.exe /C \"" + command + "\"");
现在首先我得到了.jar文件的位置。它以以下格式返回:

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
All the processes will be located here.
C:\A%20Folder\To%20YourJar\YourJar.jar
因此,需要对该位置设置以下格式

jarLocation = jarLocation.replace("%20", " ");
只需将所有%20变为空白。
注意如果目录中没有空格,则不需要上一步的格式化。
之后,我准备了实际的命令,如下所示(这是为我准备的,但您可以根据需要更改它)。
java
-在cmd中调用java程序
-cp
-执行位于jar文件内部的类。
然后我添加了jar位置,然后添加了包并添加了参数(对于主方法中的
字符串[]args
public class RebootTest implements ApplicationListener {
    private final Runnable rebootHook;
    private Stage stage;
    private Skin skin;

    public RebootTest(final Runnable rebootHook) {
        this.rebootHook = rebootHook;
    }

    @Override public void create() {
        this.stage = new Stage();
        this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));

        final Table table = new Table();
        table.setFillParent(true);

        final TextButton button = new TextButton("Reboot", this.skin);
        button.addListener(new ClickListener() {
            @Override public void clicked(final InputEvent event, final float x, final float y) {
                Gdx.app.postRunnable(RebootTest.this.rebootHook);
            }
        });

        table.add(button).expand().size(120, 40);

        this.stage.addActor(table);

        Gdx.input.setInputProcessor(this.stage);
    }

    @Override public void resize(final int width, final int height) {}

    @Override public void render() {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        this.stage.act();
        this.stage.draw();
    }

    @Override public void pause() {}

    @Override public void resume() {}

    @Override public void dispose() {
        if (this.stage != null) {
            this.stage.dispose();
        }
        if (this.skin != null) {
            this.skin.dispose();
        }
    }
}