gpt4 book ai didi

java - ThreadPoolExecutor.shutdownNow() 没有在 Thread 中抛出 InterruptedException

转载 作者:行者123 更新时间:2023-12-05 04:39:29 25 4
gpt4 key购买 nike

我正在实现一个传输服务器程序,该程序从客户端获取消息(通过控制台输入),然后将其转发到某种邮箱。

为了允许不同客户端同时接收多个消息,我首先创建了一个实现Runnable 接口(interface)的类。每个此类实例都将处理与一个客户端的通信:

public class ClientConnection implements Runnable {

//...

//...

@Override
public void run() {
try {
// prepare the input reader and output writer
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);

Message message = new Message();
String request = "";

// read client requests
while ((request = reader.readLine()) != null) {

System.out.println("Client sent the following request: " + request);
String response;
if (request.trim().equals("quit")) {
writer.println("ok bye");
return;
}

response = message.parseRequest(request);
if (message.isCompleted()) {
messagesQueue.put(message);
message = new Message();
}
writer.println(response);
}

} catch (SocketException e) {
System.out.println("ClientConnection: SocketException while handling socket: " + e.getMessage());
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (InterruptedException e) {
System.out.println("Client Connection was interrupted!");
e.printStackTrace();
} finally {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
clientSocket.close();
} catch (IOException ignored) {}
}

}

}
}

我确实有一个父线程负责启动和管理所有 ClientConnection runnables:

@Override
public void run() {

clientConnectionExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
while (true) {

Socket clientSocket;

try {
// wait for a Client to connect
clientSocket = serverSocket.accept();

ClientConnection clientConnection = new ClientConnection(clientSocket, messagesQueue);
clientConnectionExecutor.execute(clientConnection);

} catch (IOException e) {
// when this exception occurs, it means that we want to shut down everything
clientConnectionExecutor.shutdownNow(); // force terminate all ClientConnections
return;
}
}
}

现在根据this Stackoverflow Question ,我本以为一旦 shutdownNow(); 被调用,InterruptedException 就会在我的 ClientConnection.run() 中抛出方法,在那里,它应该打印 Client Connection was interrupted!。但这并没有发生,因此 catch 子句似乎永远不会到达,输入读取循环一直在继续。

我在另一个 Stackoverflow 问题中读到,这可能与 block 中的某些其他代码行有关,似乎正在消耗 InterruptedException,但没有任何关于什么代码行可以做到这一点的具体信息。所以我很感谢任何提示。

编辑:事实证明,只要我通过在客户端上键入“quit”手动退出循环,循环就会退出,然后打印 Client Connection was interrupted!。因此,只要循环正在运行,异常似乎就会以某种方式被忽略,并且只会在之后处理。

最佳答案

来自 Oracle 文档 shutdownNow :

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

如果您查看 ThreadPoolExecutor资源,你会发现shutdownNow使用此代码中断线程:

        void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}

你的 ClientConnection不检查标志 Thread.interrupted .由于帖子中的信息,我无法弄清楚哪个方法会抛出 InterruptedException .可能是其他一些方法,例如 readLine读者或作者,阻塞线程,因为他们使用套接字的 InputStreamOutputStream并且因为很明显,如果数据不是立即可用,套接字的流会阻塞线程。

例如,我写了这段代码来测试它:

class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(8080));
Socket socket = serverSocket.accept();
int dataByte = socket.getInputStream().read();
System.out.println(dataByte);
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
}
}

在 OpenJdk-16.0.2 上没有实际中断。

我看到您的问题有两种可能的解决方案:

  1. 检查 Thread.interruptedwhile里面如果您确定 Socket 则循环不会阻塞您的线程。

  2. 如果您不确定,请使用 SocketChannel在非阻塞模式下而不是 Socket用于检查 Thread.interrupted手动。

对于第二种方式,我将示例转换为:

class Example {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try(ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(8080));

SocketChannel socket = null;

while (socket == null) {
socket = serverSocket.accept();

if (Thread.interrupted()) {
throw new InterruptedException();
}
}

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socket.read(byteBuffer);
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.flip();
byteBuffer.get(bytes);
System.out.println(new String(bytes, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Interrupted successfully");
}
});
thread.start();
thread.interrupt();
}
}

有效。

祝你使用 Java :)

关于java - ThreadPoolExecutor.shutdownNow() 没有在 Thread 中抛出 InterruptedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70433737/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com