JVM关闭前的Java轮询器线程清理

JVM关闭前的Java轮询器线程清理,java,multithreading,shutdown-hook,Java,Multithreading,Shutdown Hook,我有一个Java应用程序,它有一些无限运行的线程轮询后端数据库。当JVM关闭时(通过weblogic UI),我需要对每个线程执行一些清理操作,比如连接到DB并将正在运行的事务的状态从“进行中”设置为“未处理” 有没有一种方法可以在每个线程中编写一个方法,当JVM停止线程时会调用该方法 我知道关闭钩子,但我需要线程中变量的数据来了解Db中要更改的状态,在关闭钩子的实现中,似乎启动了一个单独的钩子线程,该线程将不具有原始线程的数据。因为您可以访问这些线程(我的意思是您可以修改它们的代码)然后你可以

我有一个Java应用程序,它有一些无限运行的线程轮询后端数据库。当JVM关闭时(通过weblogic UI),我需要对每个线程执行一些清理操作,比如连接到DB并将正在运行的事务的状态从“进行中”设置为“未处理”

有没有一种方法可以在每个线程中编写一个方法,当JVM停止线程时会调用该方法


我知道关闭钩子,但我需要线程中变量的数据来了解Db中要更改的状态,在关闭钩子的实现中,似乎启动了一个单独的钩子线程,该线程将不具有原始线程的数据。

因为您可以访问这些线程(我的意思是您可以修改它们的代码)然后你可以:

  • 不允许用户以正常方式停止退出应用程序。一旦他要求你停止,你就要为他停止。这就是你需要钩子的地方。例如,如果应用程序基于
    JFrame
    ,则添加
    windowClosing()
    hook以优雅地停止运行的
    线程
    s,同时将框架的默认关闭操作设置为在关闭时不执行任何操作。请看下面这个答案中我的代码
  • 在无限循环中放置停止标志,使其成为有限循环
  • 当关闭即将发生时,更改这些标志,使每个
    线程退出循环
  • 当退出循环时,
    线程
    将进行任何必要的更改(完全访问其所有变量),然后退出
    run()
    方法
  • 同时,在主
    线程
    (即标记所有其他
    线程
    停止的
    线程
    )中,您将进入
    join()
    每个有限
    线程

    此方法允许等待
    线程
    完全执行(即退出其
    run()
    方法)
  • 最后,主
    线程将调用,例如
    系统。退出(0)
    退出整个应用程序,因为这应该是用户最后想要的操作
  • 注意:这假设用户将以正常操作关闭应用程序。例如,如果用户打算通过Windows的任务管理器终止应用程序,那么这种方法将不起作用。我不知道
    Thread
    s上的关机钩子

    下面是示例代码(请阅读注释):

    导入java.awt.event.WindowAdapter;
    导入java.awt.event.WindowEvent;
    导入javax.swing.JFrame;
    导入javax.swing.JLabel;
    公开课{
    私有静态类MyThread扩展线程{
    private boolean keepGoing=true;//这是停止标志。
    private final int i;//在本例中,我标记线程的“id”,但它也是一个任意变量,线程在其最后时刻有访问权。。。
    公众读物(最终int i){
    这个。i=i;
    }
    私有同步布尔值isKeepGoing(){
    return keepGoing;//告诉我们是否应该退出循环并开始停止操作。。。
    }
    公共同步的void startShutdown(){
    keepGoing=false;//告诉我们应该退出循环并开始停止操作。
    }
    @凌驾
    公开募捐{
    当(isKeepGoing()){//完成每个循环后,我们检查是否可以继续。
    //你的“无限”循环动作在这里:
    尝试{Thread.sleep(1000);}catch(final InterruptedException ie){}
    System.out.println(“线程”+i+“正在运行…”);
    }
    //你优雅的关机动作在这里。。。
    System.out.println(“线程”+i+”:我的停止操作在这里!看,我有权访问我的所有变量(如i)!;)”;
    }
    }
    公共静态void main(最终字符串[]args){
    //创建并启动线程:
    最终MyThread[]myThreads=新的MyThread[5];
    对于(int i=0;i
    上面应该打印如下内容:

    线程1正在运行…
    线程4正在运行…
    线程0正在运行…
    线程2正在运行…
    线程3正在运行…
    线程3正在运行…
    Th
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    
    public class GraceDown {
        private static class MyThread extends Thread {
            private boolean keepGoing = true; //This is the stopping flag.
            private final int i; //In this case i marks the 'id' of the Thread, but it is also an arbitary variable that the Thread has acccess in its final moments...
    
            public MyThread(final int i) {
                this.i = i;
            }
    
            private synchronized boolean isKeepGoing() {
                return keepGoing; //Tells if we should exit the loop and start the stopping operation...
            }
    
            public synchronized void startShutdown() {
                keepGoing = false; //Tells we should exit the loop and start the stopping operation.
            }
    
            @Override
            public void run() {
    
                while (isKeepGoing()) { //After every complete loop, we check the if we can go on.
                    //Your 'infinite' loop actions go in here:
                    try { Thread.sleep(1000); } catch (final InterruptedException ie) {}
                    System.out.println("Thread " + i + " running...");
                }
    
                //Your gracefull shutdown actions go here...
                System.out.println("Thread " + i + ": my stopping actions go here! Look, I have access to all my variables (such as i)! ;)");
            }
        }
    
        public static void main(final String[] args) {
            //Create and start the Threads:
            final MyThread[] myThreads = new MyThread[5];
            for (int i = 0; i < myThreads.length; ++i)
                myThreads[i] = new MyThread(i);
            for (int i = 0; i < myThreads.length; ++i)
                myThreads[i].start();
    
            final JFrame frame = new JFrame("Lets close me...");
            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //IMPORTANT STEP! This means we are going to close the application instead of it being closed automatically when the user presses to close the window...
    
            //Adding the 'hook':
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(final WindowEvent wevt) {
                    System.out.println("Initializing shutdown...");
                    //This is where the thread is going to stop all others...
                    for (int i = 0; i < myThreads.length; ++i)
                        myThreads[i].startShutdown();
    
                    //Wait for all threads to stop:
                    for (int i = 0; i < myThreads.length; ++i)
                        try { myThreads[i].join(); } catch (final InterruptedException ie) { System.err.println("Error gracefully shutdowning the Thread!!!"); }
    
                    //Now we can exit the JVM:
                    System.out.println("Exiting JVM...");
                    System.exit(0); //Code '0' indicates exiting without error(s).
                }
            });
    
            frame.getContentPane().add(new JLabel("Close this window and the Threads will shutdown gracefully...", JLabel.CENTER));
            frame.pack();
            frame.setLocationRelativeTo(null); //Put the packed frame on the center of the default screen.
            frame.setVisible(true);
        }
    }