Java BIO改良(伪异步IO)

请先移步查看《Java 传统的BIO编程》

Java BIO改良(伪异步IO)_第1张图片

我们将客户端请求投递到线程池中进行处理,JDK线程池维护一个消息队列和N个活跃线程,对消息队列中的任务进行处理,由于线程池可以设置对队列的大小和最大线程数,因此占用的资源是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽而宕机。

Java BIO改良(伪异步IO)_第2张图片
Java BIO改良(伪异步IO)_第3张图片
Java BIO改良(伪异步IO)_第4张图片

弊端分析:由于底层通信依然采用同步阻塞队列,因此无法从根本上解决问题。

Java InputStream:

public int read(byte b[]) throws IOException {

//This method blocks until input data is available, end of file is detected, or an exception is thrown.

        return read(b, 0, b.length);

    }

当对Socket输入流进行读取操作的时候,它会一直阻塞下去,直到发生下面3种事件:

(1)有数据可读

(2)可用数据已经读取完毕

(3)发生空指针或者IO异常

这就意味着当发送请求或者应答消息比较缓慢,或者网络传输缓慢时,读取输入流一方的通信线程将被长时间阻塞,如果一方要60S才能将数据读取完毕,读取一方的IO线程将会被阻塞60S,在此期间,其他消息只能在消息队列中排队。

当调用OutputStream的write方法写输出流的时候,它将会被阻塞直到所有要发送的字节全部写入完毕,或者发生异常。

伪异步IO无法从根本上解决同步IO导致的通信线程阻塞问题,下面我们分析一下通信对方返回应答时间过长会引起的级联故障。

1.服务器处理缓慢,返回应答消息耗费60S,平均只要10S

2.采用伪异步IO线程正在读取故障服务节点的响应,由于读取输入流是阻塞的,它将会被

阻塞60S

3.假设所有可用的线程都会被故障服务器阻塞,那后续的IO消息都将在队列中排队

4.由于线程池采用阻塞队列实现,当队列满了之后,后续入队列的操作将会被阻塞

5.由于前端只有一个ACCEPTOR线程接受客户端接入,它被阻塞在线程池的同步阻塞队列之后,新的客户端请求消息将会被拒绝,客户端发生大量的连接超时

6.由于几乎所有的连接都超时,调用者会认为系统已经崩溃,无法接受新的请求消息

如何,Java NIO将会给出答案!!!

你可能感兴趣的:(Java BIO改良(伪异步IO))