【问题标题】:What prevents program from exiting?是什么阻止程序退出?
【发布时间】:2016-08-02 09:05:19
【问题描述】:

我是这样写的。

public static void main(String[] args){
    Thread thread = new Thread(() -> {
        while(true){
            try{
                // do something
                Thread.sleep(10);
            }catch(InterruptedException ex){
                System.out.println("ABC");
                break;
            }
        }
    });
    JFrame frame = new JFrame();
    frame.setSize(1280,720);
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.addWindowListener(new WindowAdapter(){
        @Override
        public void windowClosed(WindowEvent e){
            thread.interrupt();
        }
    });
    thread.start();
    frame.setVisible(true);
}

当我点击窗口的“关闭”按钮时,
该程序需要几秒钟才能结束。
是什么阻止程序退出?
以及如何使用JFrame.EXIT_ON_CLOSE 立即关闭程序?

我认为我的线程(while(true)线程)立即结束
因为在我单击“关闭”按钮后不久就会显示“ABC”。

谢谢。

编辑

没有我的线程也会发生同样的事情。

public static void main(String[] args){
    JFrame frame = new JFrame();
    frame.setSize(1280,720);
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
}

EDIT2

public static void main(String[] args){
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        Thread[] threads = new Thread[5];
        Thread.enumerate(threads);
        System.out.println(Arrays.toString(threads));
        System.err.println(LocalDateTime.now() + " SHUTDOWN");
    }
    ));
    JFrame frame = new JFrame();
    frame.setSize(1280,720);
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.addWindowListener(new WindowAdapter(){
            @Override
            public void windowClosed(WindowEvent e){
                Thread[] threads = new Thread[5];
                Thread.enumerate(threads);
                System.out.println(Arrays.toString(threads));
                System.err.println(LocalDateTime.now() + " CLOSE");
            }
        });
    frame.setVisible(true);
}  

输出是:

[Thread[AWT-EventQueue-0,6,main], Thread[DestroyJavaVM,5,main], null, null, null]
2016-08-02T19:04:50.465 CLOSE
[Thread[DestroyJavaVM,5,main], Thread[Thread-0,5,main], null, null, null]
2016-08-02T19:04:51.762 SHUTDOWN

【问题讨论】:

  • 那是你的完整代码吗?因为thread需要初始化
  • 我无法重现这个。修复编译问题后,单击关闭按钮时立即打印ABC,程序终止。另请查看stackoverflow.com/documentation/swing/2266/… 以了解如何正确启动 Swing 应用程序。
  • @Cir0X 对不起,为了清楚起见,我编辑了代码。
  • 您可能想检查github.com/afester/CodeSamples/blob/master/Java/Swing/src/com/… 是否重现了我们的问题。如果有用,请在您的问题中随意将其用作minimal reproducible example。如果是,还要添加输出,以便每个人都知道您正在谈论的时间跨度。
  • 查看我对以下答案的评论。您观察到的行为已记录在案。

标签: java multithreading swing jframe


【解决方案1】:

虽然System.exit() 通常应谨慎使用,但Swing documentation 明确指出这是问题所示场景中的正确方法:

当 Java 虚拟机 (VM) 中的最后一个可显示窗口时 处理完毕后,VM 可能会终止。但是请注意,可以 是程序自动退出前的延迟,并且在 在某些情况下,程序可能会继续运行。 速度更快, 使用 System.exit(int) 显式退出程序更安全。

以下示例未显示关闭操作和关闭挂钩之间的延迟。删除System.exit(0) 调用时,延迟约。可以观察到 1,3 秒:

package com.example.swing;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.time.LocalDateTime;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class ExitDelay {
    public static void main(String[] args){

        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.err.println(LocalDateTime.now() + " SHUTDOWN") ));

        SwingUtilities.invokeLater(() -> {

            JFrame frame = new JFrame();
            frame.setSize(1280,720);
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.addWindowListener(new WindowAdapter(){
                @Override
                public void windowClosed(WindowEvent e){
                    System.err.println(LocalDateTime.now() + " CLOSE");

                    // Do all required cleanup stuff.
                    // check that threads are done, close files, commit transactions etc.
                    // ...

                    System.exit(0);
                }
            });
            frame.setVisible(true);

        });
    }
}

【讨论】:

    【解决方案2】:

    要立即退出程序,您可以使用System.exit(0)

    这样:

    public static void main(String[] args){
        Thread thread = new Thread(() -> {
            while(true){
                try{
                    // do something
                    Thread.sleep(10);
                }catch(InterruptedException ex){
                    System.out.println("ABC");
                    System.exit(0);
                }
            }
        });
        JFrame frame = new JFrame();
        frame.setSize(1280,720);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter(){
            @Override
            public void windowClosed(WindowEvent e){
                thread.interrupt();
            }
        });
        thread.start();
        frame.setVisible(true);
    }
    

    【讨论】:

    • 对不起,我不想使用System.exit(0),因为我想在我的线程适当终止的情况下结束程序。
    • 那很粗鲁,使DISPOSE_ON_CLOSE的使用毫无用处。
    • @Shu S System.exit(0) 在 Swing 中看起来 that 错误
    • System.exit 在那个位置也很糟糕,因为还有另一个线程在工作。
    • @specializt 通常我同意System.exit() 应该谨慎使用。但是,Swing documentation 明确表示:When the last displayable window within the Java virtual machine (VM) is disposed of, the VM may terminate. Note, however, that there can be a delay before the program exits automatically, and that under some circumstances the program might keep running. It is quicker and safer to explicitly exit the program using System.exit(int). 我会在 windowClosed() 方法中这样做。
    【解决方案3】:

    您使用DISPOSE_ON_CLOSE,这是有道理的,因为EXIT_ON_CLOSE 将使用System.exit 来关闭所有活动线程的jvm 进程。 JFrame 是一个复杂的结构,它使用一些本机调用来注册操作系统中鼠标事件的回调。所以一个干净的出口需要一些时间。此外,垃圾收集器需要一些时间来检测运行JFrameAWT-Thread 在他杀死它之前完全完成了清理工作。因此,我认为 1.3 秒对于您的应用程序的干净完成是可以接受的。
    但是如果你真的想这样做,你可以用另一个Thread 来强制结束,它只是不断地检查所有正在运行的线程是否已经完成工作并且所有JFrames 都已经消失了。如果是这样,它就称其为大恶魔System.exit


    final JFrame frame = new JFrame(); // make your JFrame final
    final Thread thread  = new Thread(() ...  // make your Thread final
    

    并添加此端检查线程

    final Thread endChecker  = new Thread(() -> {            
        while(true){
            try{
                Thread.sleep(100);
                if(!frame.isDisplayable() && !thread.isAlive())
                    System.exit(0);                 
            }catch(InterruptedException ex){
                break;
            }
        }           
    });
    endChecker.start();
    

    【讨论】:

      猜你喜欢
      • 2014-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2012-02-12
      相关资源
      最近更新 更多