“javaw.exe”在System.exit(0)之后无法退出

4
我正在编写一个Java程序,其中有一个JFrame和一个Thread。一切都很好,唯独当我点击“X”按钮关闭程序时,程序本身关闭了(框架和它的资源被销毁),但是“javaw.exe”进程不会结束。我必须手动终止它。
我尝试了setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE),甚至尝试了带有System.exit(0)的awt窗口监听器,但仍然没有成功。
还有什么想法可以帮忙解决吗?
这是我的代码。[需要在您的计算机上安装JavaCV]
class MyGrabber implements Runnable {
    final int INTERVAL = 1000;// /you may use interval
    IplImage image;
    CanvasFrame frame = new CanvasFrame("Web Cam");

    public MyGrabber() {
        frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    }

    @Override
    public void run() {
        FrameGrabber grabber = new OpenCVFrameGrabber(0); // 1 for next camera
        int i = 0;
        try {
            grabber.start();

            while (true) {
                image = grabber.grab();
                if (image != null) {
                    cvSaveImage("test.jpg", image);
                    // show image on window
                    frame.showImage(image);
                }
                Thread.sleep(INTERVAL);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (com.googlecode.javacv.FrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
}

public class TestGrabber {
    public static void main(String[] args) {
        MyGrabber gs = new MyGrabber();
        Thread th = new Thread(gs);
        th.start();
    }
}

3
如果您没有很快得到一个像样的解决方案,您可能需要提供更多的信息。考虑创建并发布一个 SSCCE - Hovercraft Full Of Eels
更多信息?比如什么?哪些部分不容易理解? - Emil
2
我不明白是什么导致了你当前的问题,我担心这是因为你发布的代码与当前的问题没有任何关系。如果我采用你上面发布的代码,进行修改以便它可以编译和运行,它并不会重现出现的问题。所以对我来说,问题可能在于未显示的代码中。我们没有时间或意愿去审查你的所有代码,但如果这是我的项目,我会尝试将代码缩减到最小的可编译和可运行的代码,以确实演示问题。然后我会在这里发布它。 - Hovercraft Full Of Eels
1
我有一种感觉,你在某个地方启动了一个非守护线程,虽然我以为System.ext(...)应该可以停止这些线程,所以我仍然感到困惑。 - Hovercraft Full Of Eels
2
您已经注册了一个线程作为关闭挂钩,如果遇到问题,请考虑使用jstack。如果进程拒绝“退出”,则很可能被卡在关闭挂钩中,实际上不需要任何代码。 - bestsss
显示剩余3条评论
3个回答

3
  • 退出程序(使用System.exit()或JFrame.EXIT_ON_CLOSE)
  • 打开任务管理器并记录进程ID(PID)
  • 打开终端窗口并输入cd c:\<path>\java\bin(将<path> 替换为您的Java安装路径)
  • 使用jstack <pid> | more命令。把<pid>替换为从任务管理器中得到的进程ID。

查看未标记为“守护进程(daemon)”的线程。至少有一个这样的线程会挂起且在堆栈跟踪中有关闭处理程序。


@Emil,这将显示问题。如果问题不清楚,请发布输出。 - Hendrik Brummermann
@HendrikBrummermann 谢谢你,让我朝着正确的方向寻找答案! - Kingsolmn

3

请记住,

The JVM will terminate only and only when 
All the Non-Daemon threads including the main thread has terminated.

You can try System.exit(0) on the main thread, which runs the main method.

尝试创建继承 JFrame 的类,然后在其构造函数中添加 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)。在主方法中使您的窗体可见时,请使用 EventQueue。例如:
public static void main(String[] args){
   EventQueue.invokeLater(new Runnable(){

   public void run(){
         myframe.setVisible
        }
   });
 }

1
我认为 System.exit(...) 实际上会停止非守护线程,这就是为什么我没有发布答案的原因。我认为 @bestsss 的想法更好。 - Hovercraft Full Of Eels

2
我认为我找到了问题所在。问题似乎出现在“grabber.start();”这一行。(因为通过注释掉那一行,一切都很好。这是openCV库显示出来的一个问题。所以我猜这个问题不会那么容易解决。
感谢大家的努力。
编辑:[找到了解决方案]
他们似乎已经实现了OpenCVFrameGrabber类中的线程Runnable接口,因此,由这个类创建的对象随后像一个线程运行。(虽然不完全相同)。
所以,作为这个问题的解决方案,我首先释放了抓取器:
public Test() {
    //canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    canvas.addWindowListener(new WindowAdapter() {

        @Override
        public void windowClosing(WindowEvent e) {
            System.out.println("\nClosing it.");
            try {
                //if (grabber != null)
                        grabber.release();
                        //grabber.stop();
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

            System.exit(0);
        }
    });
}

1
不应该从不同的线程访问 FrameGrabber,这样不能保证是线程安全的。您应该从与调用 start() 和 grab() 的相同线程中调用 grabber.stop()/release()。然后进程应该正常退出。 - Samuel Audet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接