如何在多线程Java服务器中向客户端发送ArrayList?
解决多线程服务器向客户端传输ArrayList的问题
要在Java Socket通信中传输ArrayList,核心是利用对象序列化——把Java对象转换成字节流在网络中传输,另一端再把字节流还原成对象。下面是具体实现步骤和修改后的代码:
前置准备:确保元素可序列化
ArrayList本身实现了Serializable接口,但它里面的元素也必须实现该接口,否则会抛出NotSerializableException。比如你要传输酒店数据,先定义一个可序列化的实体类:
import java.io.Serializable; public class Hotel implements Serializable { // 建议显式声明序列化版本号,避免版本不一致问题 private static final long serialVersionUID = 1L; private String name; private String address; public Hotel(String name, String address) { this.name = name; this.address = address; } @Override public String toString() { return "酒店名称:" + name + ",地址:" + address; } }
修改服务器代码
替换原有的字符流为对象流,添加触发传输ArrayList的逻辑(比如客户端发送getList指令时发送),同时修正原代码中的语法错误:
import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Collections; class Server { // 用Collections.synchronizedList保证多线程环境下的线程安全 private static final ArrayList<Object> objList = Collections.synchronizedList(new ArrayList<>()); public static void main(String[] args) { // 初始化测试数据 objList.add(new Hotel("万豪酒店", "北京朝阳区")); objList.add(new Hotel("希尔顿酒店", "上海黄浦区")); ServerSocket server = null; try { server = new ServerSocket(1234); server.setReuseAddress(true); while (true) { Socket client = server.accept(); System.out.println("新客户端连接:" + client.getInetAddress().getHostAddress()); new Thread(new ClientHandler(client)).start(); } } catch (IOException e) { e.printStackTrace(); } finally { if (server != null) { try { server.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 保留原文件读取方法,可自行修改为将文件内容转为对象加入objList private static String Read_File(String filePath) { StringBuilder builder = new StringBuilder(); try (BufferedReader buffer = new BufferedReader(new FileReader(filePath))) { String str; while ((str = buffer.readLine()) != null) { builder.append(str).append("\n"); } } catch (IOException e) { e.printStackTrace(); } return builder.toString(); } private static class ClientHandler implements Runnable { private final Socket clientSocket; public ClientHandler(Socket socket) { this.clientSocket = socket; } public void run() { ObjectOutputStream out = null; ObjectInputStream in = null; try { // 注意:必须先创建ObjectOutputStream,再创建ObjectInputStream,否则会阻塞 out = new ObjectOutputStream(clientSocket.getOutputStream()); in = new ObjectInputStream(clientSocket.getInputStream()); String line; while ((line = (String) in.readObject()) != null) { System.out.printf("客户端发送:%s\n", line); if ("getList".equalsIgnoreCase(line)) { // 发送ArrayList对象 out.writeObject(objList); out.flush(); System.out.println("已向客户端发送ArrayList"); } else { // 原回显逻辑 out.writeObject("服务器回复:" + line); out.flush(); } } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (out != null) out.close(); if (in != null) in.close(); clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
修改客户端代码
同样替换为对象流,处理服务器返回的ArrayList:
import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Scanner; class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 1234)) { ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); Scanner sc = new Scanner(System.in); String line = null; while (!"exit".equalsIgnoreCase(line)) { line = sc.nextLine(); out.writeObject(line); out.flush(); // 读取服务器返回的对象 Object response = in.readObject(); if (response instanceof ArrayList) { System.out.println("收到服务器的ArrayList:"); ArrayList<?> list = (ArrayList<?>) response; for (Object item : list) { System.out.println(item); } } else { System.out.println(response); } } sc.close(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }
关键注意事项
- 所有要传输的对象(包括ArrayList中的元素)必须实现
Serializable接口。 - 流的创建顺序:服务器和客户端都要先创建
ObjectOutputStream,再创建ObjectInputStream,否则会因等待对方的流头而阻塞。 - 多线程环境下,共享的ArrayList要保证线程安全,使用
Collections.synchronizedList或CopyOnWriteArrayList。 - 可以通过自定义指令(如
getList)触发服务器发送ArrayList,避免不必要的传输。
内容的提问来源于stack exchange,提问作者Fiordi Toska
相关产品推荐
相关产品推荐

