BIO、NIO与AIO的区别
BIO
BIO (Blocking I/O),即同步阻塞I/O。数据的读取写入必须阻塞在一个线程内等待其完成。在JDK1.4之前的IO操作都是BIO。
NIO
NIO (New I/O),也可以认为是(Non-Blocking I/O),同步非阻塞I/O,DK1.4引入的新API,它支持面向缓c存的,基于通道的I/O操作方法,提供了 Channel , Selector,Buffer等抽象。
AIO
AIO (Asynchronous I/O) - 异步IO,AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会阻塞在,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
NIO与BIO的区别
1、BIO面向流,而NIO面向的是缓冲。BIO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。NIO将数据读取到一个它稍后处理的缓冲区。
2、BIO的I/O操作是阻塞的,而NIO的I/O操作是非阻塞的。BIO在执行read/write方法时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。而NIO在执行read/write方法时,线程不阻塞,有数据就去读或者写。无需等待。
3、NIO的选择器允许一个单独的线程来监视多个通道,而BIO通常是一个线程对应一个tcp连接
4、NIO在读取数据时,因为不知道数据有没有读完,所以在处理时会复杂一点,而BIO因为线程阻塞直到读完,所以处理起来会简单一点。所以对大量连接,但是每个连接传输的数据很小的情况使用NIO会比较好,而对于连接少,但是数据传输量大的情况使用BIO会比较好。
NIO简介
Java NIO 由三个核心部分组成:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。
Channel和Buffer
基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。
Channel的种类有:FileChannel(文件)、DatagramChannel(UDP)、SocketChannel(tcp)、ServerSocketChanne(可以监听新进来的TCP连接)。
Buffer的类型有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。
Selector
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。
使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。
NIO代码示例
server:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
private int port;
private Selector selector;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
public NioServer(int port){
try {
this.port = port;
//打开一个ServerSocket通道,相当于ServerSocket
ServerSocketChannel channel = ServerSocketChannel.open();
//设置地址和端口
channel.bind(new InetSocketAddress(port));
//设置为非阻塞模式,使用selector,channel必须是非阻塞的
channel.configureBlocking(false);
//打开选择器
selector = Selector.open();
//将ServerSocket通道注册到这个Selector上
//ServerSocketChannel只能用OP_ACCEPT状态,
channel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}
public void listen(){
try {
while (true){
//这里会阻塞,等待连接
//NIO是I/O操作不会阻塞,如read和Write操作。
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()){
SelectionKey key = iter.next();
iter.remove();
process(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void process(SelectionKey key) throws IOException {
if(key.isAcceptable()){
ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel();
SocketChannel channel = serverChannel.accept();
channel.configureBlocking(false);
//连接成功,注册到selector上,设置为读监听
key = channel.register(selector,SelectionKey.OP_READ);
}else if(key.isReadable()){
//通道读已就绪
SocketChannel channel = (SocketChannel)key.channel();
//将读取到的数据放到buffe中
int len = channel.read(buffer);
if(len>0){
//将buffer从写模式切换到读模式
buffer.flip();
String content = new String(buffer.array(),0,len);
//将通道注册到selector,设置为写监听
key = channel.register(selector,SelectionKey.OP_WRITE);
//在key上携带一个附件,一会再写出去
key.attach(content);
System.out.println("读取内容:" + content);
}
}else if(key.isWritable()){
SocketChannel channel = (SocketChannel)key.channel();
String content = (String)key.attachment();
//将buffer中的数据读到通道中
channel.write(ByteBuffer.wrap(("输出:" + content).getBytes()));
channel.close();
}
}
public static void main(String[] args) {
new NioServer(8080).listen();
}
}
client:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class Nioclient {
public static void main(String[] args) throws IOException, InterruptedException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
socketChannel.configureBlocking(false);
String info = "hello server!";
buffer.put(info.getBytes());
buffer.flip();
while (buffer.hasRemaining()){
socketChannel.write(buffer);
}
buffer.clear();
Thread.currentThread().sleep(3000);
int len = socketChannel.read(buffer);
String msg = new String(buffer.array(),0,len);
System.out.println(msg);
socketChannel.close();
}
}
参考文章:https://www.cnblogs.com/diegodu/p/6823855.html
参考文章:https://www.cnblogs.com/duanxz/p/6759689.html
参考文章:https://ifeve.com/java-nio-all/