阻塞式和多线程 BIO 详解 ServerSocket实例

1.什么是IO

流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节或字符序列。从流中取得数据的操作称为读取,而向流中添加数据的操作称为写入。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出

用通俗的话讲,I就是in =进来=输入流,O就是out=出去=输出流,这里的输入输出是以内存为参考对象,即输入流可以理解为字节从硬盘内跑到内存里了,  硬盘-->内存 ,输出流是字节从内存跑到硬盘中 , 内存-->硬盘以内存为参考对象,内存出去就是输出流,要写数据,进来内存就是输入流,要读数据。IO是计算机操作系统对资源读和写的操作,可以简单理解为对资源的复制拷贝,只不过是目的地有所区别而已。初学者对IO可能会有点懵,输入输出到底是谁从哪里输入到哪里,又输出到哪里,下面参考一张图更加容易理解。

2.阻塞 非阻塞  同步  异步

阻塞和非阻塞相对于数据而言

 阻塞:在读取或者写入数据的时候,一直需要等待操作系统(内核)准备数据,若数据已经就绪,IO开始进行读或写,否则,就处于阻塞等待状态,等待数据的就绪,期间不能做其他事情,程序无法向下执行。

非阻塞:不论操作系统的数据是否已经准备好,程序都能继续往下执行,不需等待数据的就绪。

同步和异步是相对于IO事件而言,侧重的方式不一样

同步:在IO事件发生的时候,程序只能等待IO事件处理完毕,方可继续往下执行

异步:不关心IO事件是否处理完毕,让操作系统去执行该事件的同时,继续往下执行,等待该事件操作完毕时的一个通知,在往下执行的某个时候,会收到操作系统完成该事件的通知。  

3.阻塞式IO  一般称为BIO -- BlockedIO


使用jdk提供的ServerSocket  Socket套接字可以模拟服务端与客户端之间的通信,或者基于此API,封装服务器和客户端。在IO事件发生时,是处于阻塞状态的。下面看代码

服务端代码


客户端代码


执行结果:先运行服务端,再运行客户端(执行main方法);




4.多线程式IO

由于阻塞式IO有阻塞,且每次只能为一个客户端服务,多个客户端连接需要依次等待,效率很低,资源利用也少。

如果使用多线程,每次客户端连接之后,将任务放在新的线程去执行,那么多个客户端的任务执行互不干扰,可以并发的去执行。可以很大程序上解决单线程BIO的问题,这种BIO为多线程BIO。但是也有缺点,并发量太大,线程和任务比为:n:n,即一个任务需要开启一个线程处理。指数级的会消耗大量的线程,线程的开启和运行是非常消耗资源的,对CPU的负担也非常大

所以可以采用线程池的思想去解决,但是线程池在一定程序上限制了线程的数量,也会造成在海量并发情况下的等待阻塞,这种方式称为伪异步IO。

多线程IO 客户端代码不变,服务端代码稍微改造一下即可。

new Thread().start(); 传入执行的线程体,new Runable()实现run()方法


客户端复制一下TcpClient类 

运行结果:


5.非阻塞 NIO 

非阻塞式NIO  程序在发生IO事件时不会发生阻塞。此篇文章不再详解,将另开篇幅介绍。


猜你喜欢

转载自blog.csdn.net/YAO_IT/article/details/79752779