调用 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] 键(例如:注销)