You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在重写的run()方法中使用已创建对象(TCP聊天场景)

TCP点对点聊天程序线程拆分问题

我是编程初学者,正在搭建TCP点对点聊天程序,需要把任务拆分到不同线程。打算给消息发送部分(Scanner、DataOutputStream等)单独开线程,所以实现了Runnable接口,但run()方法里没法调用socket的OutputStream对象,卡了一周,求解决思路。

原代码示例

public class ClientHorcher implements Runnable {

    public static void main(String[] args) {
        
        try {
            ServerSocket serverSocket = new ServerSocket(11111);
            System.out.println("Waiting For Connection:- ");
            Socket socket = serverSocket.accept();
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
            String nickname;
            System.out.print("Gib einen Nickname ein: ");
            nickname = scanner.nextLine();
            while (true) {
                String vonMsg = datenRein.readUTF();
                System.out.println("Client:- " + vonMsg);
                if (vonMsg.equals("exit")) {
                    System.out.println("Beenden!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    serverSocket.close();
                    System.exit(0);
                }

                System.out.print(nickname + " :- ");
                String zuMsg = scanner.nextLine();
                datenRaus.writeUTF(zuMsg);
                if (zuMsg.equals("exit")) {
                    System.out.println("Quiting!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    serverSocket.close();
                    System.exit(0);
                }
            }
        } catch (IOException e) {
        
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        
        
    }

}

public class ClientVerbinder implements Runnable  {
    


    public static void main(String[] args) {

        try {
            Socket socket = new Socket("Localhost", 11111);
            System.out.println("Connected");
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
            String nickname;
            System.out.print("Gib einen Nickname ein: ");
            nickname = scanner.nextLine();

            while (true) {
                System.out.print(nickname + " :- ");
                String zuMsg = scanner.nextLine();
                datenRaus.writeUTF(zuMsg);
                if (zuMsg.equals("exit")) {
                    System.out.println("Beenden!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    System.exit(0);
                }
                String vonMsg = datenRein.readUTF();
                System.out.println("CLient" + " :- " + vonMsg);
                if (vonMsg.equals("exit")) {
                    System.out.println("Quiting!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    System.exit(0);
                }
            }
        } catch (UnknownHostException e) {
            
            e.printStackTrace();
        } catch (IOException e) {
            
            e.printStackTrace();
        }

    }
    @Override
    public void run() {
        
        
    }

}

解决思路

  • 成员变量传递依赖:把Socket、DataOutputStream、Scanner等需要在run()中使用的对象,通过线程类的构造方法传入,作为类的成员变量,这样run()方法就能直接访问这些对象。
  • 拆分读写线程:将消息读取和消息发送拆分为两个独立线程,避免单线程中读写操作互相阻塞导致程序无响应。
  • 统一资源管理:不要在循环内重复关闭资源,编写统一的资源关闭方法,在程序退出或异常时调用,保证资源正确释放。

修改后的代码示例

ClientHorcher(服务端角色)

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class ClientHorcher {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(11111);
            System.out.println("等待连接...");
            Socket socket = serverSocket.accept();
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());

            System.out.print("输入昵称: ");
            String nickname = scanner.nextLine();

            // 启动读消息线程
            Thread readThread = new Thread(new ReadRunnable(datenRein, socket, serverSocket, scanner, datenRaus));
            // 启动写消息线程
            Thread writeThread = new Thread(new WriteRunnable(datenRaus, scanner, nickname, socket, serverSocket, datenRein));

            readThread.start();
            writeThread.start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 读消息线程类
    static class ReadRunnable implements Runnable {
        private DataInputStream datenRein;
        private Socket socket;
        private ServerSocket serverSocket;
        private Scanner scanner;
        private DataOutputStream datenRaus;

        public ReadRunnable(DataInputStream datenRein, Socket socket, ServerSocket serverSocket, Scanner scanner, DataOutputStream datenRaus) {
            this.datenRein = datenRein;
            this.socket = socket;
            this.serverSocket = serverSocket;
            this.scanner = scanner;
            this.datenRaus = datenRaus;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    String vonMsg = datenRein.readUTF();
                    System.out.println("对方: " + vonMsg);
                    if (vonMsg.equals("exit")) {
                        System.out.println("对方已退出,程序结束!");
                        closeResources();
                        System.exit(0);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                closeResources();
            }
        }

        private void closeResources() {
            try {
                if (datenRein != null) datenRein.close();
                if (datenRaus != null) datenRaus.close();
                if (scanner != null) scanner.close();
                if (socket != null) socket.close();
                if (serverSocket != null) serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 写消息线程类
    static class WriteRunnable implements Runnable {
        private DataOutputStream datenRaus;
        private Scanner scanner;
        private String nickname;
        private Socket socket;
        private ServerSocket serverSocket;
        private DataInputStream datenRein;

        public WriteRunnable(DataOutputStream datenRaus, Scanner scanner, String nickname, Socket socket, ServerSocket serverSocket, DataInputStream datenRein) {
            this.datenRaus = datenRaus;
            this.scanner = scanner;
            this.nickname = nickname;
            this.socket = socket;
            this.serverSocket = serverSocket;
            this.datenRein = datenRein;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    System.out.print(nickname + ": ");
                    String zuMsg = scanner.nextLine();
                    datenRaus.writeUTF(zuMsg);
                    if (zuMsg.equals("exit")) {
                        System.out.println("已退出,程序结束!");
                        closeResources();
                        System.exit(0);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                closeResources();
            }
        }

        private void closeResources() {
            try {
                if (datenRein != null) datenRein.close();
                if (datenRaus != null) datenRaus.close();
                if (scanner != null) scanner.close();
                if (socket != null) socket.close();
                if (serverSocket != null) serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

ClientVerbinder(客户端角色)

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class ClientVerbinder {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 11111);
            System.out.println("已连接");
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());

            System.out.print("输入昵称: ");
            String nickname = scanner.nextLine();

            // 启动读消息线程
            Thread readThread = new Thread(new ReadRunnable(datenRein, socket, scanner, datenRaus));
            // 启动写消息线程
            Thread writeThread = new Thread(new WriteRunnable(datenRaus, scanner, nickname, socket, datenRein));

            readThread.start();
            writeThread.start();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 读消息线程类
    static class ReadRunnable implements Runnable {
        private DataInputStream datenRein;
        private Socket socket;
        private Scanner scanner;
        private DataOutputStream datenRaus;

        public ReadRunnable(DataInputStream datenRein, Socket socket, Scanner scanner, DataOutputStream datenRaus) {
            this.datenRein = datenRein;
            this.socket = socket;
            this.scanner = scanner;
            this.datenRaus = datenRaus;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    String vonMsg = datenRein.readUTF();
                    System.out.println("对方: " + vonMsg);
                    if (vonMsg.equals("exit")) {
                        System.out.println("对方已退出,程序结束!");
                        closeResources();
                        System.exit(0);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                closeResources();
            }
        }

        private void closeResources() {
            try {
                if (datenRein != null) datenRein.close();
                if (datenRaus != null) datenRaus.close();
                if (scanner != null) scanner.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 写消息线程类
    static class WriteRunnable implements Runnable {
        private DataOutputStream datenRaus;
        private Scanner scanner;
        private String nickname;
        private Socket socket;
        private DataInputStream datenRein;

        public WriteRunnable(DataOutputStream datenRaus, Scanner scanner, String nickname, Socket socket, DataInputStream datenRein) {
            this.datenRaus = datenRaus;
            this.scanner = scanner;
            this.nickname = nickname;
            this.socket = socket;
            this.datenRein = datenRein;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    System.out.print(nickname + ": ");
                    String zuMsg = scanner.nextLine();
                    datenRaus.writeUTF(zuMsg);
                    if (zuMsg.equals("exit")) {
                        System.out.println("已退出,程序结束!");
                        closeResources();
                        System.exit(0);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                closeResources();
            }
        }

        private void closeResources() {
            try {
                if (datenRein != null) datenRein.close();
                if (datenRaus != null) datenRaus.close();
                if (scanner != null) scanner.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Ljonja2107

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:45:43