Java 调用LinkedList.add时线程挂起

Java 调用LinkedList.add时线程挂起,java,multithreading,serversocket,Java,Multithreading,Serversocket,所以我写了两个服务器套接字。一个侦听端口8085上的HTTP请求并将字节输入保存到静态LinkedList中,另一个侦听端口8086并在静态LinkedList中返回所有结果 问题是,当将数据从ServerSocket:8085保存到LinkedList时,线程挂起,我不知道为什么 这是主侦听器类: import java.net.ServerSocket; import java.nio.charset.Charset; import java.util.*; public class Li

所以我写了两个服务器套接字。一个侦听端口8085上的HTTP请求并将字节输入保存到静态LinkedList中,另一个侦听端口8086并在静态LinkedList中返回所有结果

问题是,当将数据从ServerSocket:8085保存到LinkedList时,线程挂起,我不知道为什么

这是主侦听器类:

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();
            }

        }


    }
}
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
未同步化

您可以手动处理同步、使用同步列表或并发列表。可能还有其他一些方法,但现在,请保持简单

public static LinkedList<byte[]> Calls = Collections.synchronizedList(new LinkedList<>());

// or

public static LinkedList<byte[]> Calls = new CopyOnWriteArrayList<>();
publicstaticLinkedList调用=Collections.synchronizedList(newLinkedList());
//或
public static LinkedList Calls=new CopyOnWriteArrayList();

A
LinkedList
未同步化

您可以手动处理同步、使用同步列表或并发列表。可能还有其他一些方法,但现在,请保持简单

public static LinkedList<byte[]> Calls = Collections.synchronizedList(new LinkedList<>());

// or

public static LinkedList<byte[]> Calls = new CopyOnWriteArrayList<>();
publicstaticLinkedList调用=Collections.synchronizedList(newLinkedList());
//或
public static LinkedList Calls=new CopyOnWriteArrayList();

您使用浏览器创建请求的测试机制在这里可能也没有帮助,因为
InputStream.readAllBytes()

块,直到读取完所有剩余字节并检测到流结束,或引发异常。此方法不会关闭输入流

从。具体来说,浏览器保持连接打开,因为它期待一些响应。您的服务器正在尝试从连接读取所有内容,直到连接关闭。第22条(又称死锁)

尝试使用
telnet
连接到
localhost:8085
,然后关闭客户端的连接


其中,
^D
实际上是[CTRL]和[D]键(例如:注销)

您使用浏览器创建请求的测试机制在这里可能也没有帮助,因为
InputStream.readAllBytes()

块,直到读取完所有剩余字节并检测到流结束,或引发异常。此方法不会关闭输入流

从。具体来说,浏览器保持连接打开,因为它期待一些响应。您的服务器正在尝试从连接读取所有内容,直到连接关闭。第22条(又称死锁)

尝试使用
telnet
连接到
localhost:8085
,然后关闭客户端的连接


其中,
^D
实际上是[CTRL]和[D]键(例如:注销)

除了同步问题之外,谁在向8085服务器写入数据?在那里写入的应用程序是否在完成对流的写入后关闭流?如果它是一个程序,也显示它的代码。如果没有,请解释是如何做到的。请在问题中添加信息,不要使用评论,除非告诉我们您已更新。updated@real怀疑您的同步方法是错误的。不要使用同步静态方法。它们在类对象上同步,如果使用
wait
notify
,可能会导致问题。此外,如果只在写入时同步,而在读取时忽略同步,那么同步就没有任何意义。迭代器在运行时更改
调用
。那太糟糕了。您应该使用阻塞队列。除了同步问题之外,谁在向8085服务器写入数据?在那里写入的应用程序是否在完成对流的写入后关闭流?如果它是一个程序,也显示它的代码。如果没有,请解释是如何做到的。请在问题中添加信息,不要使用评论,除非告诉我们您已更新。updated@real怀疑您的同步方法是错误的。不要使用同步静态方法。它们在类对象上同步,如果使用
wait
notify
,可能会导致问题。此外,如果只在写入时同步,而在读取时忽略同步,那么同步就没有任何意义。迭代器在运行时更改
调用
。那太糟糕了。您应该改为使用阻塞队列。添加同步方法有效,我现在仍在处理连接重置问题。添加同步方法有效,我现在仍在处理连接重置问题。正确,切换到
socket.getInputStream().readNBytes(socket.getInputStream().available())
解决了这个问题。太棒了。我想知道在同一个问题上是否有多个不同答案的徽章来获得选票;-)@TomasBreuer该方法(使用可用的
)是错误的。这意味着您只读取本地缓冲的字节,但如果发送的通信比本地缓冲区大,
available()
将不会反映完整的文本。请仔细阅读
available()
的文档。正确,切换到
socket.getInputStream().readNBytes(socket.getInputStream().available())
解决了这个问题。太棒了。我想知道在同一个问题上是否有多个不同答案的徽章来获得选票;-)@TomasBreuer该方法(使用可用的
)是错误的。这意味着你在