结束线程的执行而不使用其 stop() 方法



我有一个带有按钮的 Swing 表单,当单击时开始SocketServer用于侦听单独线程中的传入请求。以下是我拥有的类的结构。

  • MainForm:这是我启动摇摆表单的主要课程。它有两个按钮,"启动服务器"和"停止按钮"。
  • MySocketServer:这个类是对象存在SocketServer,它有方法startServer()stopServer()

以下是"开始"按钮的单击事件正文。

t = new Thread(new Runnable() //Object t is created globally in this main class.
{
    public void run()
    {
        myss = new MySocketServer(); //Object myss has similar accessibility as t.
        myss.startServer();
    }
});
t.start();

以下是停止按钮的单击事件正文

myss.stopServer();
if(t.isAlive());
    System.out.println("Thread is still alive!!");

虽然我可以根据需要切换SockeServer"开始"和"停止",但我意识到每次启动服务器时,都会创建新线程,即使使用MySocketServer方法停止服务器,它仍然保持活动状态。

我可以使用stop() Thread并停止线程执行,但由于它已贬值,并且我研究过线程在run()方法完全执行后就会结束,但是我将startServer()方法分开,以便它可以单独处理连接的客户端。

请注意,startServer()具有 While-Listen 循环,因此本质上run()线程方法处于无限执行状态,直到我显式调用 stopServer() 并停止循环。

这里能做什么?

首先,您不尝试使用Thread.stop()是对的。 这是潜在的危险。

那你应该怎么做?

一种可能性可能是像这样编写服务器线程:

    ....
    ServerSocket ss = new ServerSocket(...);
    try {
       while (keepGoing) {
           Socket s = ss.accept(...);
           try {
               // do stuff
           } finally {
               // close socket
           }
       }
    } finally {
       // close the server socket
    }

stopServer清除keepGoing旗。 但问题是,当线程在accept调用中被阻塞时,通常会停止,并且没有任何东西可以取消阻止它。

另一种可能性可能是在线程上调用Thread.interrupt()。 这会导致某些事情解锁并引发异常,但我认为它不会解锁accept()调用。 (但是,如果"做事"部分需要中断,这仍然比设置标志要好。

真正的解决方案(我认为)是关闭ServerSocket. 这将导致ss.accept()调用取消阻止并引发异常,您需要在服务器线程中处理该异常。

在 while 循环的 MySocketServer 类中,您需要一个标志来测试它是否应该继续运行。

在新添加的关闭方法中,设置线程中的循环将测试的标志。一旦循环中断并 run() 返回,线程将结束。

你不应该使用 stop()。看看这个 http://docs.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html具有无限循环和启动/停止标志的解决方案很简单,但会导致 CPU 时间的使用效率低下。更好的方法是使用等待/通知方法。你使用 MySocketServer 操作的方式让我觉得你在 startServer() 中还有其他无限循环。这就是为什么你必须阻止它。最好在内部将此循环包装到它自己的线程中,并使启动/停止方法以等待/通知方式使用此线程状态运行。忘了提一下,由于您的 GUI 在自己的线程中运行,您无法在 MySocketServer 中转义启动/停止标志,因为在 GUI 线程中使用 wait() 会使其挂起。

最新更新