0

我试图让我的 Java 应用程序关闭,但线程保持打开状态。

当使用默认的 windows x 按钮单击关闭时,一切正常(可能是由于 EXIT_ON_CLOSE?) - 但是当我使用编程按钮时,它挂在 thread.join() 上。

更糟糕的是,窗口处理得很好,所以用户会认为它是关闭的——然而有几个 AWT 线程保持打开状态。我的主线程正在等待 id 为 20 的线程,但我不知道如何获取线程 ID。

有没有人有什么建议?

这是我的退出代码:

public synchronized void stop() {
    running = false;
    frame.dispose();
    WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
    try {
        if (server != null) {
            server.exit();
        }
        client.exit();
        thread.join();
        new Thread(){
            public void run() {
                System.exit(0);
            }
        }.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        e.printStackTrace();
        System.exit(1);
    }
}

这是退出后打开的线程:

线程-eclipse

这是我的run()方法的内容:

public void run() {
    requestFocus();
    while (running) {
        getTimer().tick();
        if (System.currentTimeMillis() - getTimer().getSecond() > 1000) {
            // every second, add a second, print fps and mod title with fps
            getTimer().accumulateSecond();
            //System.out.println(getTimer().returnFPS());
            frame.setTitle(title + "  |  " + getTimer().returnFPS());
            getTimer().resetTick();
            ticker++;
        }
        while (getTimer().getDelta() >= 1) {
            // every time delta goes greater than one, update and supertick
            update();
            getTimer().superTick();
        }
        if (getTimer().getFPS() > 100) {
            try {
                Thread.sleep(5);
            } catch (Exception e) {
                System.err.println("Sleeping failed: " + e);
            }
        } 
        render();
        if (ticker > 30) {
            ticker = 0;
            getTimer().hourTick();
        }

    }
    stop();
}
4

1 回答 1

0

更新:

在看到更多代码后,我很确定您的问题是您正在从一个线程调用stop()(即)。synchronized在内部stop(),您调用thread.join(),它会尝试等待thread实例完成其run()方法。设置running标志会导致run()退出其while循环,但方法中的最后一行代码是对stop(). 如果这是您向我们展示的相同 stop()方法,那么您有一个deadlock

方法内部的stop()调用run()将永远无法进入该方法,因为第一个线程仍在内部stop()并等待run()完成(它永远不会,因为它正在等待能够调用并进入stop())。僵局。

您将不得不从 inside 中删除对的调用stop()run()或者找到另一种方法来修改您的代码。


我不会担心识别特定的线程 ID。担心让所有线程正确完成。

首先,Thread#join()停止线程。它等待它完成。您正在做的其他事情必须导致/允许thread实例完成其run()方法。

我看到的唯一可能做到这一点的是设置

    running = false;

您的thread对象是否在其方法中检查该标志run()?例如:

public void run() {
    while (isRunning()) {

        // do some work
        Thread.sleep(delay);
    }
}

哪里isRunning()会返回running变量的值?

现在,我不能说没有看到更多的代码。但是,您可能已经选择这样实现isRunning()

public synchronized boolean isRunning() {
    return running;
}

如果你这样做了,那就有问题了。主线程将按照stop()您向我们展示的方法获取锁。然后它将进行thread.join()调用,此时它开始等待工作线程。如果工作线程随后调用isRunning()在同一个锁上同步的,isRunning()则将阻塞,因为锁已经由于主线程在里面而被持有stop()

如果thread对象试图从您向我们展示其代码的类synchronized中调用任何其他方法,则可能会出现相同的基本问题。

长话短说,我们需要查看更多代码(thread变量所代表的线程中正在运行的代码)。但是,您可能在这里遇到了僵局。

在此处阅读有关优雅停止线程的更多信息

于 2013-05-31T01:56:11.020 回答