阻塞IO实战与总结

2020-06-18  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读