一.什么是IO
所谓IO即input和output的缩写,是对数据的流入和流出的一种抽象,编程中很常见的一个概念。
二. 什么是流
体会一下这几个词:水流(静止的水想必没人会叫水流),物流,人流(此人流非彼人流 = =!),可以发现流的特点:动态的,可转移的,从一处到另一处的
三.java io
java为了我们调用方便,而屏蔽输入/输出源和流动细节,抽象出的用于解决数据流动问题的类体系,这就是java的io流
传统java.io包提供了诸如File的抽象,输入,输出流。交互方式是同步,阻塞;
第二,在java1.4中引入NIO框架(java.nio包),提供了Channel,Selector,Buffer等抽象,构建多路复用的,同步非阻塞IO,同时提供了更接近操作系统底层的高性能数据操作方式
第三,在Java 7中,NIO有了进一步的改进,也就是NIO 2。其引入了异步非阻塞IO方式,或者说AIO(Asynchronous IO)。异步IO基于事件和回调机制。
传统Sckoet IO的比喻图:
这里可以看到将系统比喻成餐厅,serverScoket监听端口就相当于大门,客人相当于scoket客户端,线程相当于服务员。这里看到传统IO是单线程的,即一个服务员只能服务一个客人。
我们首先来看传统的一段scoket编程
package OIO;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 传统socket服务端
* @author -琴兽-
*
*/
public class OioServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//创建socket服务,监听10101端口
ServerSocket server=new ServerSocket(10101);
System.out.println("服务器启动!");
while(true){
//获取一个套接字(阻塞)
final Socket socket = server.accept();
System.out.println("来个一个新客户端!");
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
//业务处理
handler(socket);
}
});
}
}
/**
* 读取数据
* @param socket
* @throws Exception
*/
public static void handler(Socket socket){
try {
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while(true){
//读取数据(阻塞)
int read = inputStream.read(bytes);
if(read != -1){
System.out.println(new String(bytes, 0, read));
}else{
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
System.out.println("socket关闭");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这里用的是线程池创建的scoket,可以解决单线程的服务器的缺点,必竟单线程情况下只能有一个客户端
但是用线程池可以有多个客户端连接,但是非常消耗性能。就比如说饭店一个服务员只能对一个顾客服务吗?
故传送IO特点:
阻塞点
server.accept();
inputStream.read(bytes);
单线程情况下只能有一个客户端
用线程池可以有多个客户端连接,但是非常消耗性能
四.什么是NIO
NIO的流程图:
这里看到还是将系统比喻成餐厅,ServerSocketChannel.socket相当于大门,客人相当于客户端,线程加selector相当于服务员。
与传统IO不同的是这里是一个服务员可以服务多个客人
在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O速度非常慢,而在Java 1.4中推出了NIO,这是一个面向块的I/O系统,系统以块的方式处理处理,每一个操作在一步中产生或者消费一个数据库,按块处理要比按字节处理数据快的多。
NIO通过线程的轮询,实现非阻塞IO
在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。
- Buffer 缓冲区;高效的数据容器 ,不同的是BIO将数据直接读写到Stream对象中 NIO的数据操作都是在缓冲区中进行的 ,缓冲区实际上是一个数组,常见类型ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloutBuffer,DoubleBuffer
- Channel 在NIO中被用来支持批量式IO操作的一种抽象,与流不同,通道是双向的。 File/Socket,通常被认为是比较高层次的抽象,而Channel则是更加偏向操作系统底层的一种抽象,这也使得NIO得以充分利用现代操作系统底层机制,进行性能优化。分两大类:网络读写SelectableChannel(子类包括SocketChannel和ServerSocketChannel);文件操作(FileChannel)
- Selector 是NIO实现多路复用的基础。它提供一种高效机制,不断轮询注册在其上的Channel,找出处于就绪状态,通过SelectionKey取得就绪的Channel集合,进行后续的IO操作。服务端只要提供一个负责Selector轮询的线程即可,实现单线程对多Channel的高效管理,也是基于操作系统底层机制
- Charset 提供Unicode字符串定义,NIO也提供了相应的编解码等