Java NIO技术

概述

一、NIO简介

  • NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)
  • NIO基于 Channel 和 Buffer 进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中
  • Selector用于监听多个通道的事件(比如:连接打开,数据到达),单个线程可以监听多个数据通道

二、NIO VS 传统IO

  • IO是面向流的,NIO是面向缓冲区的:NIO中的缓冲区的存在使我们可以在其中对数据进行操作,增加了灵活性
  • IO的各种流是阻塞的,NIO是非阻塞模式:Selector用于监听多个通道的事件,从而实现一个线程管理多个输入和输出通道

三、Channel & Buffer & Selector

1、channel

  • 传统IO中的stream是单向的,而 NIO 中的channel是双向的,既可读又可写;
  • NIO中的Channel的主要实现有:这几个实现分别对应 IO、UDP、TCP
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel

2、buffer

  • NIO中的关键Buffer实现有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应几种基本的数据类型
  • NIO中还有MappedByteBuffer, HeapByteBuffer, DirectByteBuffer等

3、selector

  • 要使用Selector, 得向Selector注册Channel,然后调用select()方法,这个方法会一直阻塞到某个注册的通道有事件就绪
  • 事件就绪后这个方法返回,线程就可以处理这些事件,事件的例子有如新的连接进来、数据接收等

FileChannel

一、NIO的实例

public static void method1(){
   
	RandomAccessFile aFile = null;
	try{
   
		aFile = new RandomAccessFile("d:\\123.txt","rw");
		FileChannel fileChannel = aFile.getChannel();
		ByteBuffer buf = ByteBuffer.allocate(1024);
		int bytesRead = fileChannel.read(buf);
		System.out.println(bytesRead);
		while(bytesRead != -1)
		{
   
			buf.flip();
			while(buf.hasRemaining())
			{
   
				System.out.print((char)buf.get());
			}
			buf.compact();
			bytesRead = fileChannel.read(buf);
		}
	}catch (IOException e){
   
		e.printStackTrace();
	}finally{
   
		try{
   
			if(aFile != null){
   
				aFile.close();
			}
		}catch (IOException e){
   
			e.printStackTrace();
		}
	}
}

二、buffer 使用

1、基本原理

  • buffer 的本质是一个容器,是一个连续的数组;
  • NIO 数据传递的基本过程如图:
    在这里插入图片描述
  • 向Buffer中写数据:
    从Channel写到Buffer (fileChannel.read(buf))
    通过Buffer的put()方法 (buf.put(…))
  • 从Buffer中读数据:
    从Buffer读取到Channel (channel.write(buf))
    使用get()方法从Buffer中读取数据 (buf.get())

2、详细使用步骤描述

buffer的几个参数
  • capacity:指定了可以存储在缓冲区中的最大数据容量
  • position:指的是下一个要被读写的元素的数组下标索引,该值会随get()和put()的调用自动更新
  • limit:指的是缓冲区中第一个不能读写的元素的数组下标索引,也可以认为是缓冲区中实际元素的数量
  • mark:一个备忘位置,调用mark()方法的话,mark值将存储当前position的值,等下次调用reset()方法时,会设定position的值为之前的标记值
  • 四个参数之间的大小关系为:0 <= mark <= position <= limit <= capacity
buffer的实际使用过程
  • 创建一个容量大小为10的字符缓冲区:ByteBuffer bf = ByteBuffer.allocate(10);
    在这里插入图片描述
  • 往缓冲区中put()五个字节:bf.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'0');
    在这里插入图片描述
  • 调用flip()方法,切换为读就绪状态:bf.flip()
    在这里插入图片描述
  • 读取两个元素:System.out.println("" + (char) bf.get() + (char) bf.get());
    在这里插入图片描述
  • 标记此时的position位置:bf.mark()
    在这里插入图片描述
  • 读取两个元素后,恢复到之前mark的位置处:
System.out.println("" + (char) bf.get() + (char) bf.get());
bf.reset();

在这里插入图片描述

  • 调用compact()方法,释放已读数据的空间,准备重新填充缓存区:bf.compact() ; 这里要是调用 clear 方法的话,position将被设回0,limit设置成capacity
    在这里插入图片描述

SocketChannel

一、概述

  • NIO的channel抽象的一个重要特征就是可以通过配置它的阻塞行为,以实现非阻塞式的信道
    channel.configureBlocking(false)

二、TCP示例

1、client 使用 NIO

public static void client(){
   
	ByteBuffer buffer = ByteBuffer.allocate(1024);
	SocketChannel socketChannel = null;
	try
	{
   
		socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));
		if(socketChannel.finishConnect())
		{
   
			int i=0;
			while(true)
			{
   
				TimeUnit.SECONDS.sleep(1);
				String info = "I'm "+i+++"-th information from client";
				buffer.clear();
				buffer.put(info.getBytes());
				buffer.flip();
				while(buffer.hasRemaining()){
   
					System.out.println(buffer);
					socketChannel.write(buffer);
				}
			}
		}
	}
	catch (IOException | InterruptedException e)
	{
   
		e.printStackTrace();
	}
	finally{
   
		try{
   
			if(socketChannel!=null){
   
				socketChannel.close();
			}
		}catch(IOException e){
   
			e.printStackTrace();
		}
	}
}

2、server 使用 BIO

public static void server(){
   
	ServerSocket serverSocket = null;
	InputStream in = null;
	try
	{
   
		serverSocket = new ServerSocket(8080);
		int recvMsgSize = 0;
		byte[] recvBuf = new byte[1024];
		while(true
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值