Java如何在程序关闭时停止线程?

4

我遇到一些异常,需要知道程序何时关闭自身,因为我需要关闭套接字。

我有默认的公共静态主方法,在其中重复执行一个操作和一个线程类。

private static Thread thread;
public static boolean isRunning = true;  

public static void main(String[] args){

   thread = new Thread(new ThreadListenServer());
   thread.start();

   Timer timer = new Timer();
   TimerTask task = new TimerTask() {
      @Override
      public void run(){
         // some action
      }
   }

   timer.scheduleAtFixedRate(task, 0, 10000);

   isRunning = false;
}

同时,还有在后台运行的线程类:

public class ThreadListenServer implements Runnable{

    private DatagramSocket socket;

    public ThreadListenServer() throws SocketException{
       socket = new DatagramSocket(6655);
    }

    @Override
    public void run() {

       while(MainProgram.isRunning){
            // some action
       }

       socket.close();
    }
}

我不知道为什么,但是 isRunning 变成了 false,但是它不应该这样。如果主程序已关闭,我该如何关闭套接字?(这是因为线程仍然在后台运行,即使程序已关闭)。
我考虑在主类中创建套接字,然后将套接字对象作为参数传递给 ThreadClass,如果程序已关闭,则也应该关闭套接字。

当您关闭一个进程时,它将关闭所有资源,包括套接字。 - Peter Lawrey
它变成了假,因为你将其设置为假。 - Peter Lawrey
考虑使用Executors而不是单独的线程。当它们完成时,更容易重新获得控制。 - Thorbjørn Ravn Andersen
4个回答

4

使用:

thread.setDaemon(true);

这将关闭线程。它告诉JVM这是一个后台线程,因此将在退出时关闭。

2
我假设您正在运行一个名为MainProgram的JFrame类。您有两个选择: 1:设置您的JFrame在关闭时关闭所有线程。
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

2:添加一个窗口监听器并手动关闭您的线程(在关闭它之前,您可能需要通过套接字发送一些信息)

addWindowListener(new WindowAdapter() {
  public void windowClosing(WindowEvent e) {
    // send your socket its close message and shut everything down
    System.exit(0);
  }
});

JVM只有在所有非守护线程终止时才会退出,这对OP的问题没有任何影响。 - MadProgrammer
请查看文档以获得更好的描述。 - MadProgrammer
@MadProgrammer 我知道守护线程,但默认情况下线程不是守护线程,我也没有看到 OP 设置它们为守护线程。此外,调用 System.exit 应该关闭所有这些线程。如果没有关闭,那么选项 2 仍然可行(并且在我看来是最好的选择),向所有线程发送关闭消息并关闭应用程序。 - ug_
默认情况下,线程不是守护线程。当JVM退出时,操作员线程不会被JVM自动终止,并且将允许其运行直到其自行退出。我也没有看到任何与swing有关的证据,对于代码示例、注释或标签,所以最好这只是一个注释,最坏的情况下就是猜测。 - MadProgrammer

2

有几件事需要考虑。

  1. 看起来您正在使用套接字执行阻塞I/O操作。您可能需要中断运行的线程和/或套接字以停止阻塞。
  2. 在启动线程之前,应将线程设置为守护线程,使用 setDaemon(true)。这将允许JVM自动终止线程...
  3. isRunning 应标记为 volatile 或者您应该使用 AtomicBoolean 替代。

1
为了在程序正常退出时停止所有线程,您需要为每个启动的线程定义终止策略。通常使用中断和ExecutorService.shutdownNow()方法来发送中断信号到每个正在运行的线程来完成此操作。
一个清洁的终止策略包含两个部分:
1. 向线程发送停止信号 - 即中断它 2. 设计线程以响应中断
在Java中,可以通过调用Thread.interrupt()方法来中断线程。线程可以通过调用Thread.isInterrupted()方法来检查中断。一个好的线程必须定期检查中断,例如作为循环条件,并检查阻塞函数是否有InterruptedExceptions。
需要注意的是,Java中的Socket对中断是无感知的。例如,如果一个线程被阻塞在Socket.accept()上,当线程被中断时,它不会抛出InterruptedException。在这种情况下,您需要定义一个公共方法,通过调用Socket.close()关闭底层套接字,强制阻塞函数抛出异常(我猜测是SocketException)。

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