调用 LinkedList.add 时线程挂起
Thread hanging when calling LinkedList.add
所以我正在编写两个 ServerSocket。一个在端口 8085 上侦听 HTTP 请求并将字节输入保存到静态 LinkedList 中,另一个在端口 8086 上侦听并将 returns 所有结果保存在静态 LinkedList 中。
问题是,将数据从 ServerSocket:8085 保存到 LinkedList 时,线程挂起,我不确定为什么。
这是主要的监听器class:
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.*;
public class Listener {
public static LinkedList<byte[]> Calls = new LinkedList<>();
public static void main(String[] args) {
Thread callback = new Thread(new ThreadListener());
callback.start();
while (true) {
try (var listener = new ServerSocket(8086)) {
System.out.println("Listening on 8086...");
try (var client = listener.accept()) {
StringBuffer response = new StringBuffer();
response.append("HTTP/1.1 200 OK\r\n\r\n");
Iterator<byte[]> iterator = Calls.iterator();
while (iterator.hasNext()) {
response.append(new String(iterator.next(), Charset.forName("UTF-8")) + "\r\n");
iterator.remove();
}
client.getOutputStream().write(response.toString().getBytes("UTF-8"));
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这是 ThreadListener class:
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Date;
public class ThreadListener implements Runnable {
@Override
public void run() {
while (true) {
try (var listener = new ServerSocket(8085)) {
System.out.println("Listening on 8085...");
try (var socket = listener.accept()) {
if (!socket.getInetAddress().getHostAddress().equals("127.0.0.1")) {
System.out.println("Not localhost");
} else {
System.out.println("Its us!");
}
Listener.Calls.add(socket.getInputStream().readAllBytes());
System.out.println("Result collected");
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
至于我的测试,我尝试调用 127.0.0.1:8085,我得到一个 ERR_CONNECTION_RESET,控制台中的所有内容如下:
Listening on 8085...
Listening on 8086...
Its us!
Process finished with exit code -1 (I killed the app after 2 mins)
"Its us!" 消息被打印出来,但 LinkedList.add 之后的 "Results collected!" 没有打印出来,这一事实让我假设 LinkedList.add 是一个挂线
此致
编辑:没有人拨打 8085(或 8086),我在浏览器上手动拨打。我通过创建调用方法而不是直接调用 LinkedList.add 来解决同步问题:
public static synchronized void addElementsToList(byte[] bytes) {
Calls.add(bytes);
}
这确实有效,但每次调用 8085 套接字都会重置连接。
A LinkedList
不是 synchornized
, as highlighted in the documentation.
您可以手动处理同步、使用同步列表或并发列表。可能还有一些其他方法,但现在,保持简单。
public static LinkedList<byte[]> Calls = Collections.synchronizedList(new LinkedList<>());
// or
public static LinkedList<byte[]> Calls = new CopyOnWriteArrayList<>();
您使用浏览器创建请求的测试机制可能也无济于事,因为 InputStream.readAllBytes()
blocks until all remaining bytes have been read and end of stream is detected, or an exception is thrown. This method does not close the input stream.
来自 the documentation。具体来说,浏览器保持连接打开,因为它期待一些响应。您的服务器正在尝试从连接 读取所有内容,直到连接关闭 。 Catch 22(又名死锁)。
尝试使用 telnet
与 localhost:8085
建立连接并从客户端关闭连接。
telnet 127.0.0.1 8085
^D
其中 ^D
字面意思是 [CTRL] 和 [D] 键(例如:注销)
所以我正在编写两个 ServerSocket。一个在端口 8085 上侦听 HTTP 请求并将字节输入保存到静态 LinkedList 中,另一个在端口 8086 上侦听并将 returns 所有结果保存在静态 LinkedList 中。
问题是,将数据从 ServerSocket:8085 保存到 LinkedList 时,线程挂起,我不确定为什么。
这是主要的监听器class:
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.*;
public class Listener {
public static LinkedList<byte[]> Calls = new LinkedList<>();
public static void main(String[] args) {
Thread callback = new Thread(new ThreadListener());
callback.start();
while (true) {
try (var listener = new ServerSocket(8086)) {
System.out.println("Listening on 8086...");
try (var client = listener.accept()) {
StringBuffer response = new StringBuffer();
response.append("HTTP/1.1 200 OK\r\n\r\n");
Iterator<byte[]> iterator = Calls.iterator();
while (iterator.hasNext()) {
response.append(new String(iterator.next(), Charset.forName("UTF-8")) + "\r\n");
iterator.remove();
}
client.getOutputStream().write(response.toString().getBytes("UTF-8"));
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这是 ThreadListener class:
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Date;
public class ThreadListener implements Runnable {
@Override
public void run() {
while (true) {
try (var listener = new ServerSocket(8085)) {
System.out.println("Listening on 8085...");
try (var socket = listener.accept()) {
if (!socket.getInetAddress().getHostAddress().equals("127.0.0.1")) {
System.out.println("Not localhost");
} else {
System.out.println("Its us!");
}
Listener.Calls.add(socket.getInputStream().readAllBytes());
System.out.println("Result collected");
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
至于我的测试,我尝试调用 127.0.0.1:8085,我得到一个 ERR_CONNECTION_RESET,控制台中的所有内容如下:
Listening on 8085...
Listening on 8086...
Its us!
Process finished with exit code -1 (I killed the app after 2 mins)
"Its us!" 消息被打印出来,但 LinkedList.add 之后的 "Results collected!" 没有打印出来,这一事实让我假设 LinkedList.add 是一个挂线
此致
编辑:没有人拨打 8085(或 8086),我在浏览器上手动拨打。我通过创建调用方法而不是直接调用 LinkedList.add 来解决同步问题:
public static synchronized void addElementsToList(byte[] bytes) {
Calls.add(bytes);
}
这确实有效,但每次调用 8085 套接字都会重置连接。
A LinkedList
不是 synchornized
, as highlighted in the documentation.
您可以手动处理同步、使用同步列表或并发列表。可能还有一些其他方法,但现在,保持简单。
public static LinkedList<byte[]> Calls = Collections.synchronizedList(new LinkedList<>());
// or
public static LinkedList<byte[]> Calls = new CopyOnWriteArrayList<>();
您使用浏览器创建请求的测试机制可能也无济于事,因为 InputStream.readAllBytes()
blocks until all remaining bytes have been read and end of stream is detected, or an exception is thrown. This method does not close the input stream.
来自 the documentation。具体来说,浏览器保持连接打开,因为它期待一些响应。您的服务器正在尝试从连接 读取所有内容,直到连接关闭 。 Catch 22(又名死锁)。
尝试使用 telnet
与 localhost:8085
建立连接并从客户端关闭连接。
telnet 127.0.0.1 8085
^D
其中 ^D
字面意思是 [CTRL] 和 [D] 键(例如:注销)