Java--IO基础

总结一下,除了异步非阻塞I/O=UNIX 异步IO 其他I/O模型都是阻塞的:

  1. 同步阻塞I/O=UNIX 阻塞I/O 同步在用户线程轮询,阻塞在数据未就绪和就绪后的复制
  2. 同步非阻塞I/O=UNIX 非阻塞I/O 同步在用户线程轮询,数据未就绪时不阻塞,阻塞在就绪后复制
  3. 同步非阻塞I/O=UNIX 多路复用I/O 同步在用户线程轮询,数据未就绪时不阻塞,阻塞在就绪后复制但与UNIX 非阻塞I/O区别在于,由一个线程来维护多个非阻塞通道,属于轻微加强版
  4. 异步阻塞I/O=UNIX 信号驱动I/O 内核通知是否就绪,数据未就绪时不阻塞,阻塞在就绪后复制
  5. 异步非阻塞I/O=UNIX 异步IO 内核通知是否就绪,绝对不阻塞

同步/异步IO——在于消息通知
阻塞/非阻塞IO——在于数据未就绪时阻塞么?数据就绪时,需要用户线程等待数据从内核复制到用户空间么?
异步I/O需要操作系统的支持

服务器接收客户端发过来的请求,想要进行处理,1. 等待数据到达 2. 拷贝到用户空间

1、同步阻塞IO

在这里插入图片描述

2、同步非阻塞IO

在这里插入图片描述
非阻塞IO基于状态轮训的方式,虽然能让程序在等待的过程中做点其他的事情,但是频繁的切换运行程序,反而会造成很大的压力。

3、IO多路复用/事件驱动

在这里插入图片描述
其实Nio或者Netty就是基于这种模式,一个线程就可以监听很多IO操作,这样在IO等待上就高效多了。具体实现是依赖于操作系统的,windows和linux都有不同的实现方式。最初的select或者poll,都有并发数的限制,并且NIO的select还有空轮训的问题;epool则突破了连接数的限制,一个线程就可以监听大量的IO操作。

4、 信号驱动IO

在这里插入图片描述
不过UNIX网络编程里面的信号驱动,可没这么简单,这个信号是依赖于操作系统底层的,捕获信号或者处理都很麻烦,所以现在应用的也不是很广泛

5、 异步非阻塞IO

在这里插入图片描述
消息的等待和处理都在服务器端完成,用户只要最后接收到消息处理完的通知就行了。


输入流与输出流

// 字符输入流操作
Reader reader = new CharArrayReader("abcd".toCharArray());
data = reader.read();
while(data != -1){
    System.out.println((char)data);
    data = reader.read();
}
// 字符输出流
CharArrayWriter writer = new CharArrayWriter();
writer.write("12345".toCharArray());
char[] wc = writer.toCharArray();

用完后释放资源,将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,Java会确保外部资源的close方法被调用。

try (FileInputStream inputStream = new FileInputStream(new File("test"))) {
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    }

BIO阻塞服务器
问题:
服务端与客户端的连接相当于1:1,因此如果连接数上升,服务器的压力会很大;
如果主线程Acceptor阻塞,那么整个服务器将会阻塞,单点问题严重;
线程数膨胀后,整个服务器性能都会下降;

import io.netty.util.CharsetUtil;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class PlainOioServer {
    public void serve(int port) throws IOException {
        // 开启Socket服务器,并监听端口
        final ServerSocket socket = new ServerSocket(port);
        try{
            for(;;){
                // 轮训接收监听
                final Socket clientSocket = socket.accept();
                try {
                    Thread.sleep(500000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("accepted connection from "+clientSocket);
                // 创建新线程处理请求
                new Thread(()->{
                   OutputStream out;
                   try{
                       out = clientSocket.getOutputStream();
                       out.write("Hi\r\n".getBytes(CharsetUtil.UTF_8));
                       out.flush();
                   } catch (IOException e) {
                       e.printStackTrace();
                   } finally {
                       try{
                           clientSocket.close();
                       } catch (IOException e) {
                           e.printStackTrace();
                       }
                   }
                }).start();
            }
        } catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws IOException {
        PlainOioServer server = new PlainOioServer();
        server.serve(5555);
    }
}

NIO

nio non-blocking-IO,可以理解非阻塞IO。
在这里插入图片描述

Buffer

/**
mark -- 标记位,标记一下position的位置,可以调用reset()方法回到这个位置
posistion -- 位置,写模式下表示开始写入的位置,读模式下表示开始读的位置
limit -- 剩余,在写模式下初始的时候等于capacity;在读模式下,等于最后一次写入的位置
capacity -- 容量,这个值是一开始申请就确定好的,类似c语言申请数组的大小
**/
Buffer(int mark, int pos, int lim, int cap) {       // package-private
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            this.mark = mark;
        }
    }

NIO的Buffer有两种模式,初始时候是写模式,利用flip()可以切换读模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值