0

抱歉标题我真的不知道如何将问题放入标题中,如果有人可以更好地提出问题,请更正它!

所以无论如何,在我的程序中,我有 2 个线程,一个是主程序,运行 GUI 以及与用户有关的所有内容,当它创建时,它创建一个线程,仅用于检查网站以查看是否有任何更新可用到程序使用的 SQLite 数据库,如果有,它会以 JSON 格式提取信息,然后必须使用插入查询更新数据库(这显然是通过围绕数据库解析器的同步方法完成的,以确保用户'在更新数据库时不访问数据)。这一切都很好。

但是,当程序关闭并且主类终止时,更新线程也必须尽快停止,但是它可能需要停止与数据库交互并关闭它,以及中断自身。我认为我需要中断线程并在数据库打开时关闭数据库,但是如何在主线程死后立即触发它?它不使用循环,所以我无法检查 thread1 是否还活着......

这是迄今为止更新程序的重要代码:

public static class AutomaticUpdater extends Thread
{
    DictionaryGUI pGUI;
    DatabaseParser pParser;

    public void run()
    {
        Updater pUpdater = new Updater (pParser, pGUI, true); //the manual updater is used to process the data
        for (String sURL : getURLs()) //getURLS() returns areas in the website that contain relevant data
        {
            pUpdater.process(getData(sURL)); //create the INSERT statements and send to database
        }
    }
}

那么当主线程死亡时,我如何确保更新程序死亡?被 JVM 杀死的线程是否会抛出异常或进行任何类型的清理函数调用,我可以覆盖以杀死更新程序并关闭数据库?

编辑:好的,我找到了解决方案,但我仍然愿意接受更好的想法......

这是附加到 GUI 的 JFrame 的:

private class ProgramCleaner implements WindowListener
{
    public void windowClosing(WindowEvent e)
    {
        MainLauncher.pAutoUpdater.kill();
    }

    public void windowActivated(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
}

其中 kill 中断更新程序并确保数据库已关闭:D

编辑2 :似乎当GUI关闭时,程序几乎总是在所有清理完成发出InterruptedException ,我用一些调试语句证明了这一点,而且我发送错误的调试文件没有选择它up (即程序完全关闭)并且异常的堆栈跟踪从不谈论我的代码或与此相关的任何内容:

Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.ref.ReferenceQueue.remove(Unknown Source)
    at java.lang.ref.ReferenceQueue.remove(Unknown Source)
    at sun.java2d.Disposer.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

有人知道为什么会这样吗?wait 在我的代码中实际上从未被称为,所以它必须是别的东西......

4

2 回答 2

1

最简单的方法是在启动之前创建AutomaticUpdater一个守护线程:

AutomaticUpdater au = new AutomaticUpdater();
au.setDaemon(true);
au.start();

将线程设置为守护线程意味着它将在程序中的所有用户级线程终止后立即终止。Main 是一个用户级线程,所以如果它是您在程序中运行的唯一用户级线程,那么这应该可以工作。你不会收到任何通知,你的更新线程只会默默地死去(我假设这就是你想要的)。

第二种选择是在代码中的某处放置一个布尔值,告诉更新线程何时停止。您可以在更新程序的 for 循环中检查该布尔值,并在布尔值切换为 false 时立即返回。

boolean running = true; //somewhere near the top of your class

...

//main launches the updater thread here

...

//inside updater's run() method:
for (String sURL : getURLs()){
    if(!running) return;
    pUpdater.process(getData(sURL));
}

编辑

这一切都假定您为访问数据库而调用的库不运行它们自己的用户级线程。如果他们这样做了,那么您将需要在代码中的某处明确停止这些线程,以使这些解决方案中的任何一个都可以工作。

于 2013-02-18T17:25:16.783 回答
0

你应该:

  1. 考虑使用调度的 executortimerQuartz,而不是滚动您自己的周期性处理器。使用计划服务,您可以调用shutdownNow,使用计时器任务,您可以调用cancel以尝试停止当前和未来的作业。

如果您决定坚持当前的设计,那么您应该:

  1. 在更新程序上设计一个显式关闭方法,并在退出应用程序之前从主线程调用它。
  2. 实施Runnable,而不是扩展Thread
于 2013-02-18T17:27:13.757 回答