BIO,NIO,AIO详解
Posted truestoriesavici01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BIO,NIO,AIO详解相关的知识,希望对你有一定的参考价值。
Java中的IO,BIO,NIO,AIO详解
IO
BIO,NIO和AIO的关系
- BIO:
java.io
包.基于流模型实现,使用同步,阻塞方式.即:读输入流或写输出流时,在读或写动作完成之前,读(写)线程一直阻塞.性能差. - NIO:
java.nio
包.可以构建多路复用,同步非阻塞的IO操作. - AIO:Java 1.7之后引入的包.提供异步非阻塞的IO操作.基于事件和回调机制实现的.程序操作后直接返回,不阻塞,后台完成处理后,由系统通知相应的线程进行后续的操作.
IO的分类
InputStream
,OutputStream
:基于字节操作的IO.Writer
,Reader
:基于字符操作的IO.File
:基于磁盘操作的IO.Socket
:基于网络操作的IO.
IO的使用
InputStream
的使用
InputStream inputStream = new FileInputStream("src\IOBIONIOAIO.md");
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
String str = new String(bytes);
inputStream.close();
System.out.println(str);
OutputStream
的使用
OutputStream outputStream = null;
outputStream = new FileOutputStream("src\IOBIONIOAIO.md",true);
outputStream.write("
OutputStream测试".getBytes("utf-8"));
outputStream.close();
Writer
的使用
Writer writer = new FileWriter("src\IOBIONIOAIO.md",true);
writer.append("
使用Writer向文件写入数据");
writer.close();
Reader
的使用
Reader reader = new FileReader("src\IOBIONIOAIO.md");
BufferedReader br = new BufferedReader(reader);
StringBuffer sb = new StringBuffer();
String str = null;
while ((str = br.readLine()) != null){
sb.append(str+"
");
}
br.close();
reader.close();
System.out.println(sb.toString());
同步,异步,阻塞,非阻塞
同步与异步
同步
- 一个任务的完成依赖于另外一个任务.
- 只有被依赖的任务完成后,依赖的任务才算完成.
异步
- 依赖的任务通知被依赖的任务要完成的任务后,完成自身的任务即算作完成.
- 被依赖的任务是否真正完成,依赖的任务无法确定.
阻塞和非阻塞
阻塞
调用结果返回之前,当前线程会被挂起.调用线程只有在得到结果之后才返回.
非阻塞
在没有得到结果之前,不会阻塞当前线程.
线程可以在结果返回之前完成其他任务,提高了CPU的利用率.
问题:系统的线程切换增加,需要权衡增加的CPU使用时间和线程切换的成本.
同/异,阻/非阻塞的组合
组合方式 | 性能 |
---|---|
同步阻塞 | I/O性能差,CPU大部分在空闲状态 |
同步非阻塞 | 提升I/O性能,增加CPU消耗 |
异步阻塞 | 对I/O能够提升效率 |
异步非阻塞 | 集群之间的消息同步机制 |
文件读写
// 使用FileWriter向文件写入数据
public void fileWriterTest() throws IOException {
FileWriter fw = new FileWriter("src\IOBIONIOAIO.md",true);
fw.write("
来自FileWriter写入的内容");
fw.close();
}
// 使用FileReader读取文件的内容
public void fileReaderTest() throws IOException {
FileReader fr = new FileReader("src\IOBIONIOAIO.md");
BufferedReader br = new BufferedReader(fr);
StringBuffer sb = new StringBuffer();
String str;
while ((str = br.readLine())!=null){
sb.append(str+"
");
}
br.close();
fr.close();
System.out.println(sb.toString());
}
使用java.nio
包中的Files
实现对文件的读写:
public void filesWrite() throws IOException {
Files.write(Paths.get("src\IOBIONIOAIO.md"),"
使用Files向文件写入数据".getBytes(), StandardOpenOption.APPEND);
}
public void filesRead() throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get("src\IOBIONIOAIO.md"));
System.out.println(new String(bytes).toString());
}
Socket和NIO的多路复用
传统的Socket实现
服务器只给客户端发消息.
客户端将接收到的消息打印.
/**
* 服务器端:
* 调用accept()阻塞线程等待客户端连接.
* 客户端连接后将数据传输过去
*/
public void servers(){
Thread thread = new Thread(() -> {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket socket = serverSocket.accept();
try (PrintWriter printWriter = new PrintWriter(socket.getOutputStream())) {
printWriter.println("来自于服务器端的消息");
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
thread.start();
}
/**
* 客户端:
* 打开指定的socket端口,
* 使用BufferedReader读取端口传来的数据
*/
public void client(){
try (Socket socket = new Socket(InetAddress.getLocalHost(),port)){
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
br.lines().forEach(s-> System.out.println(s));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
示意图:
NIO多路复用
public void servers(){
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4, 60l, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
threadPool.execute(()->{
try (Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()){
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(),port));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true){
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
try(SocketChannel channel = ((ServerSocketChannel)key.channel()).accept()){
channel.write(Charset.defaultCharset().encode("来自服务器通过NIO写入数据"));
}
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
public void client(){
try (Socket cSocket = new Socket(InetAddress.getLocalHost(),port)){
BufferedReader br = new BufferedReader(new InputStreamReader(cSocket.getInputStream()));
br.lines().forEach(s-> System.out.println(s));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
流程:
- 通过
Selector.open()
建立一个Selector
,充当调度员. - 创建一个
ServerSocketChannel
,并向Selector
注册,通过指定的SelectionKey.OP_ACCEPT
告诉调度员,关注的是新的连接请求. - 配置非阻塞模式,否则注册行为抛出异常.
Selector
阻塞在select
操作,当有Channel
发生接入请求时,就会被唤醒.
示意图:
参考:
以上是关于BIO,NIO,AIO详解的主要内容,如果未能解决你的问题,请参考以下文章