如何安全地将线程生命周期联系在一起,涉及SQLite

时间:2013-02-18 17:16:23

标签: java multithreading sqlite termination

对于我无法确定如何将问题放入标题的标题感到抱歉,如果有人能把它放得更好,请纠正它!

所以无论如何,在我的程序中我有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中断updater并确保数据库关闭:D

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

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)

有人知道为什么会这样吗?等待从来没有实际调用inmy代码所以它必须是其他东西......

2 个答案:

答案 0 :(得分:1)

最简单的方法是在启动之前制作AutomaticUpdater deamon 主题:

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

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

第二个选项是在代码中的某处放置一个布尔值,告诉updater线程何时停止。您可以在更新程序的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));
}

修改

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

答案 1 :(得分:0)

你应该:

  1. 考虑使用scheduled executortimerQuartz,而不是滚动自己的定期处理器。使用预定服务,您可以致电shutdownNow,通过计时器任务,您可以致电cancel以尝试停止当前和未来的工作。
  2. 如果您决定坚持使用当前的设计,那么您应该:

    1. 在更新程序上设计显式关机方法,并在退出应用程序之前从主线程中调用它。
    2. 实施Runnable,而不是扩展Thread