Java开发中,我们实现多线程,有两种方式, 一种是继承Thread类,一种是实现Runnable接口。
    会出现资源耗尽:
    image.png
    image.png
    image.png

    1. package com.itheima.d8_socket4;
    2. import java.io.OutputStream;
    3. import java.io.PrintStream;
    4. import java.net.Socket;
    5. import java.util.Scanner;
    6. /**
    7. 拓展:使用线程池优化:实现通信。
    8. */
    9. public class ClientDemo1 {
    10. public static void main(String[] args) {
    11. try {
    12. System.out.println("====客户端启动===");
    13. // 1、创建Socket通信管道请求有服务端的连接
    14. // public Socket(String host, int port)
    15. // 参数一:服务端的IP地址
    16. // 参数二:服务端的端口
    17. Socket socket = new Socket("127.0.0.1", 6666);
    18. // 2、从socket通信管道中得到一个字节输出流 负责发送数据
    19. OutputStream os = socket.getOutputStream();
    20. // 3、把低级的字节流包装成打印流
    21. PrintStream ps = new PrintStream(os);
    22. Scanner sc = new Scanner(System.in);
    23. while (true) {
    24. System.out.println("请说:");
    25. String msg = sc.nextLine();
    26. // 4、发送消息
    27. ps.println(msg);
    28. ps.flush();
    29. }
    30. // 关闭资源。
    31. // socket.close();
    32. } catch (Exception e) {
    33. e.printStackTrace();
    34. }
    35. }
    36. }
    1. package com.itheima.d8_socket4;
    2. import java.net.ServerSocket;
    3. import java.net.Socket;
    4. import java.util.concurrent.*;
    5. /**
    6. 目标:实现服务端可以同时处理多个客户端的消息。
    7. */
    8. public class ServerDemo2 {
    9. // 使用静态变量记住一个线程池对象
    10. private static ExecutorService pool = new ThreadPoolExecutor(300,
    11. 1500, 6, TimeUnit.SECONDS,
    12. new ArrayBlockingQueue<>(2)
    13. , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    14. public static void main(String[] args) {
    15. try {
    16. System.out.println("===服务端启动成功===");
    17. // 1、注册端口
    18. ServerSocket serverSocket = new ServerSocket(6666);
    19. // a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。
    20. while (true) {
    21. // 2、每接收到一个客户端的Socket管道,
    22. Socket socket = serverSocket.accept();
    23. System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");
    24. // 任务对象负责读取消息。
    25. Runnable target = new ServerReaderRunnable(socket);
    26. pool.execute(target);
    27. }
    28. } catch (Exception e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. }
    package com.itheima.d8_socket4;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    public class ServerReaderRunnable implements Runnable{
        private Socket socket;
        public ServerReaderRunnable(Socket socket){
            this.socket = socket;
        }
        @Override
        public void run() {
            try {
                // 3、从socket通信管道中得到一个字节输入流
                InputStream is = socket.getInputStream();
                // 4、把字节输入流包装成缓冲字符输入流进行消息的接收
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                // 5、按照行读取消息
                String msg;
                while ((msg = br.readLine()) != null){
                    System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);
                }
            } catch (Exception e) {
                System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
            }
        }
    }