(五)微服务底层通信和协议--2篇

懒驴 2021年12月04日 1,571次浏览

Java网络编程

伪异步I/O编程

在文章微服务底层通信和协议--1篇中,我对传统的BIO编程做了介绍,现在来看看伪异步I/O编程
前面提到的线程暴增,服务器宕机,那么可以使用线程池来管理这些线程,实现一个或多个线程处理N个客户端的请求模型,但是其底层还是使用同步阻塞I/O,通常被称为“伪异步I/O模型”。

伪异步I/O通信模型

如果我们使用缓存线程池,CachedThreadPool线程池,除了能够自动帮我们管理线程(复用)外,看起来就像1:1的客户端线程数模型,而使用FixedThreadPool(固定长度线程池)可以有效的控制线程的最大数量,保证系统有限资源的控制,实现N:M的伪异步I/O模型。但是,正因为限制了数量,如果发生大量并发请求,超过最大数量的线程就只能等待,直到线程池中有空闲的线程可以被复用。
当对Socket的输入流进行读取操作的时候,它会一直阻塞,直到发生下面情况:

  1. 有数据可读。
  2. 可用数据以及读取完毕。
  3. 发生空指针或I/O异常。

所以在读取数据较慢时(比如数据量大、网络传输慢等),大量并发情况下,其他接入的消息只能一直等待,这就是最大的弊端。而后面学习的NIO就可以解决这个问题。

接下来将微服务底层通信和协议--1篇中的ServerBetter类做一下修改,代码如下:

package com.study.socket.weiio;

import com.study.socket.ServerHandler;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * 伪异步I/O编程模式
 */
public class ServerBetter {
    private static int DEFAULT_PORT = 1234;        //默认的端口号
    /**单例的ServerSocket**/
    private static ServerSocket server;

    /**1. 线程池 懒汉式的单例**/
    private static ExecutorService executorService = Executors.newFixedThreadPool(60);
    /**根据传入参数设置监听端口,如果没有参数,就调用默认的方法**/
    public static void start() throws IOException {
        //使用默认端口
        start(DEFAULT_PORT);
    }

    //这里我们使用synchronized,因为这个方法不会被大量访问,不太需要考虑效率,直接进行方法同步就可以
    public synchronized static void start(int port) throws IOException {
        if (server != null) {
            return;
        }
        try{
            //2. 通过构造函数创建ServerSocket,如果端口合法且空闲,服务端就会监听成功
            server = new ServerSocket(port);
            //3. 通过无限循环监听客户端连接,如果没有客户端接入,将阻塞在accept操作上
            while (true){
                Socket socket = server.accept();
                System.out.println("服务器已经气都没回,端口号为:"+port);
                //4. 当有新的客户端接入时,创建一个新的线程处理这条Socket链路
                //注释掉旧版的
                //new Thread(new ServerHandler(socket)).start();

                /**改为新版**/
                //从线程池中获取一个新的线程处理这条Socket链路
                executorService.execute(new ServerHandler(socket));
            }
        }finally {
            //5. 服务器关闭时,清理相关的资源
            if(server != null){
                System.out.println("服务器已经关闭!");
                server.close();
                server = null;
            }
        }
    }
}

以上就是对伪异步I/O编程做的简单介绍,下面的文章将介绍NIO编程