如何解除阻塞在ServerSocket.accept()上阻塞的线程?
我有一个服务器线程与此代码:
public void run() { try { ServerSocket server; EneaLog.printLog("Server is running."); server = new ServerSocket(this.portnumber); while (true) { new EneaServerConnection(server.accept(), this.project,stopped).start(); if (stopped) { EneaLog.printLog("Server safe-shutdown completed."); EneaLog.printLog("Hi!"); server.close(); return; } } } catch (IOException ex) { Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex); project.getExceptionHandler().handler(ex); } }
和这样的关机方法:
public void shutdown() { EneaLog.printLog("Server shutdown NOW!"); stopped = true; }
我希望关闭可以解除在server.accept()上等待的线程,否则我必须在服务器关闭之前等待连接。
我不能在shutdown()中执行server.close()因为我必须向注册客户端发信号通知服务器正在关闭。
有任何想法吗?
我尝试设计我的代码,以便它可以通过中断“关闭”。 主要是因为Java的并Executor
中的Executor
框架使用interrupt
来取消正在运行的任务。 此外,“关闭”任务不必知道正在被杀死的任务的任何内部。
但是,对accept
的调用不会响应中断, 除非它是从ServerSocketChannel
创建的。 使用ServerSocket
构造函数创建的服务器将忽略中断,我还没有找到重新配置它的方法。
如果您无法更改创建服务器的代码,请安排另一个线程在服务器套接字上调用close
。 无论用于创建服务器套接字的方法如何,这也会在accept
阻塞的线程中引发exception。
使用SSL时,这是一个非常大的痛苦。 JSSE套接字不是从InterruptibleChannel
创建的,也不会响应线程上的简单中断。
我刚刚注意到问题是在没有通知客户端的情况下无法关闭服务器。 成功中断套接字会导致其关闭。
在accept
此调用的调用应该不是问题,因为如果服务器套接字在accept中被阻止,则客户端未连接。 这应该只是Socket
实例的一个问题,它代表当前的连接。
如果这不满足通知要求,则可能需要在非阻塞模式下使用NIO的ServerSocketChannel
进行返工。
您应该能够从另一个线程关闭套接字。
中断(这取决于中断点以相同的方式取消取决于取消点)也不会关闭(接受不响应关闭其文件描述符)。 您必须与accept(尝试sendto,带有关闭通知)进行通信,以通知它不继续接受。 至少在Linux上就是这种情况; 不知道在其他平台上是什么样的。
我一直面临着同样的问题。 我的工作解决方案包括关闭ServerSocket对象(serverSocket.close()); 这样做会导致accept()方法抛出SocketException,这是你想要做的。
文森特
你试过Thread.interrupt()吗?
如果此线程在可中断通道上的I / O操作中被阻塞,则通道将被关闭,线程的中断状态将被设置,并且线程将收到ClosedByInterruptException。
如果此线程在Selector中被阻塞,则线程的中断状态将被设置,并且它将立即从选择操作返回,可能具有非零值,就像调用选择器的唤醒方法一样。