美文网首页
阻塞IO实战与总结

阻塞IO实战与总结

作者: 奋斗的韭菜汪 | 来源:发表于2020-06-18 16:54 被阅读0次

    使用场景:在并发量低的情况下是适用的。


    image.png

    服务端:

    public class SocketServerDemo {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            BufferedReader in = null;
            BufferedWriter out = null;
            try {
                //监听8080端口
                serverSocket = new ServerSocket(8080);
                //阻塞等待客户端连接(连接阻塞)
                Socket socket = serverSocket.accept();
                //通过InputStream()接收数据
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println("接收到客户端的消息 : " + in.readLine());
                //写回去,通过OutputStream()发送数据
                out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                //通过\n告诉接收端消息发送结束
                out.write("服务端回复的消息\n");
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    out.close();
                    in.close();
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    客户端

    public class SocketClientDemo {
        public static void main(String[] args) {
            Socket socket = null;
            BufferedReader in = null;
            BufferedWriter out = null;
            try {
                socket = new Socket("localhost", 8080);
                //在这里睡眠100秒,当前客户端启动会IO阻塞在当前位置,如果服务端是单线程处      
                //理,启动第二个不睡眠的socketClient(自身不阻塞),第二个也会阻塞在第一个后面
                 //如何解决这个问题:可以在服务端开辟多个线程同时处理来自不同客户端的socket连接
                Thread.sleep(100000);
                //发送消息到服务端
                out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                //通过\n告诉接收端消息发送结束
                out.write("我是客户端发送了一个消息\n");
                out.flush();
                //接收来自服务端的消息
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println("来自服务端的消息:" + in.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                try {
                    in.close();
                    out.close();
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    如何解决服务同时处理多个socketClient时IO阻塞问题:可以在服务端开辟多个线程同时处理来自不同客户端的socket连接
    服务端优化代码如下:
    服务端

    public class SocketThread implements Runnable {
        private Socket socket;
        public SocketThread(Socket socket) {
            this.socket = socket;
        }
        public void run() {
            BufferedReader in = null;
            BufferedWriter out = null;
            try {
                //通过InputStream()接收数据
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println("接收到客户端的消息 : " + in.readLine());
                //写回去,通过OutputStream()发送数据
                out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                //通过\n告诉接收端消息发送结束
                out.write("服务端回复的消息\n");
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    out.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class SocketServer {
        static ExecutorService executorService = newFixedThreadPool(20);
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            //监听8080端口
            try {
                serverSocket = new ServerSocket(8080);
                while (true){
                    Socket socket = serverSocket.accept();
                    //异步
                    executorService.execute(new SocketThread(socket));
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    总结:上面虽然优化了IO 的处理方式,但是,不管是线程池还是单个线程,线程本身的处理个数是有限制的,对于操作系统来说,如果线程数太多会造成 CPU 上下文切换的开销。因此这种方式在高并发场景下不能解决根本问题,所以引入了非阻塞io
    非阻塞io:https://www.jianshu.com/p/f510084d1a3b

    相关文章

      网友评论

          本文标题:阻塞IO实战与总结

          本文链接:https://www.haomeiwen.com/subject/nsiuxktx.html