java NIO

1 篇文章 0 订阅

同步/异步,阻塞/非阻塞

可参考:https://zhuanlan.zhihu.com/p/23488863

  1. 同步:如果有多个任务需要处理,这些任务必须逐个处理,一个任务的执行会导致整个流程的等待
  2. 异步:如果有多个任务需要处理,这些任务可以并发处理,一个任务的执行不会导致整个流程的等待
  3. 阻塞:某个任务执行,他发出一个请求,但是由于条件不满足,导致一直等待直到条件满足
  4. 非阻塞:某个人物执行,他发出一个请求,条件不满足则返回一个标志告知,不会一直等待
    因此同步/异步和阻塞/非阻塞没有必联的关系,至于为什么有时候会感觉两者有联系呢?是因为java中为了使多线程同步,会用上锁的方式锁住某一共享资源,等待锁的线程就被阻塞了,感觉上为了同步就有了阻塞。其实不然,因为同步/异步和阻塞/非阻塞概念产生的前提是不一样的,前两者是多任务,后者是单任务执行过程中遇到阻碍
    可参考 java 同步/异步IO和阻塞/非阻塞IO 关系和概念解析

java中NIO跟IO的区别

IONIO
面向流(单向)面向缓冲区(双向)
阻塞式非阻塞式
选择器

NIO详解

缓冲区

  1. 在java nio中负责数据存取。缓冲区就是数组,用于储存不同数据类型的数据,根据类型不同,提供能相应的缓冲区(boolean除外),缓冲区的管理方式几乎一致,通过allocate()来获取缓冲区
    1. ByteBuffer
    2. ShortBuffer
    3. IntBuffer
    4. LongBuffer
    5. floatBuffer
    6. doubleBuffer
    7. charBuffer
  2. 缓冲区的两个核心方法:
    1. put():存入数据到缓冲区
    2. get():获取缓冲区中的数据
  3. 缓冲区的四个核心属性
    1. capacity:容量,表示缓冲区中最大存储数据的容量,一旦声明不允许改变;
    2. limit:界限,表示缓冲区中可以操作数据的大小,(limit后的数据不能进行读写)
    3. position:位置,表示缓冲区中正在操作数据的位置。
    4. mark:标记,表示记录当前position的位置,可以通过reset恢复到mark的位置;
    5. mark<position<limit<capacity
  4. 缓冲区其他方法
    1. flip:切换成读取模式,实际上是修改limit为当前position,然后修改position为0;
    2. rewind:重新读取,limit不变,position修改成0;
      flip跟rewind的区别就是,limit会不会改变;
    3. clear:清空缓冲区,但是缓冲区中的数据依然存在,但是处于被遗忘状态,意思就是关于数据的缓冲区位置指针重置了;
    4. hasRemaining:判断缓冲区中是否还有数据;
    5. remaining:返回缓冲区剩余数据的长度 limit-position
  5. 直接缓冲区与非直接缓冲区
    1. 非直接缓冲区:通过allocate方法分配缓存区,将缓冲区建立在JVM的内存中
    2. 直接缓冲区:通过allocatedirect方法分配直接缓冲区,将缓冲区建立在物理内存中;
    3. isDirect可以判断是否直接缓冲区;

通道

  1. 通道:用于源节点与目标节点的连接。在java NIO中负责缓冲区中数据的传输。Channal本身不储存数据,因此需要配合缓冲区进行传输;
  2. 通道的主要实现类
    1. java.nio.channels.Channel接口:
      1. FileChannel
      2. SocketChannel
      3. serverSocketChannel
      4. DatagramChannel
  3. 获取通道
    1. java针对支持通道的类提供了getChannel方法
      1. FileInputStream/FileOutputStream
      2. RandomAccessFile
      3. Socket
      4. serversocket
      5. DatagramSocket
    2. 在jdk7中的nio2针对各个通道提供能静态方法open();
    3. 在jdk7中的nio2的Files工具类的newByteChannel();
  4. 示例
    1. 使用流获取channel
      在这里插入图片描述
    2. 使用open方法
      在这里插入图片描述
    3. 同2类似开启通道,都是使用物理内存直接缓冲区,只不过这里是通道直接传输;
      在这里插入图片描述
  5. 分散与聚集
    1. 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
      在这里插入图片描述
    2. 聚集写入(gathering Writes):将多个缓冲区的数据聚集到通道中;
      在这里插入图片描述
  6. 字符集
    1. 编码:字符串到字节数组
    2. 解码:字节数组到字符串
      在这里插入图片描述
      其中框出来的需要注意,不管是编码还是解码都需要将变成读模式,不然没有输出;

网络传输

选择器



	@Test
	public void client() throws IOException {
		SocketChannel channel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
		
		//指定为非阻塞模式
		channel.configureBlocking(false);
		
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		
		buffer.put(new Date().toString().getBytes());
		
		buffer.flip();
		
		channel.write(buffer);
		
		buffer.clear();
		
		channel.close();
		
	}
	
	@Test
	public void server() throws IOException {
		//1.获取通道
		ServerSocketChannel channel = ServerSocketChannel.open();
		//2.切换非阻塞
		channel.configureBlocking(false);
		//3.绑定端口
		channel.bind(new InetSocketAddress(9898));
		//4.获取选择器
		Selector selector = Selector.open();
		
		//5.注册选择器并指定监听事件
		channel.register(selector, SelectionKey.OP_ACCEPT);
		
		//6.轮询获取选择器上已经准备就绪的事件
		while(selector.select() > 0) {
			//7.获取已经准备就绪的事件迭代器
			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			
			while(iterator.hasNext()) {
				//8.获取事件
				SelectionKey selectionKey = iterator.next();
				//9.判断事件是否是接收事件
				if(selectionKey.isAcceptable()) {
					//10.若是接收事件,则才开启连接(可以新建线程)
					SocketChannel clientChannel = channel.accept();
					//11.切换非阻塞
					clientChannel.configureBlocking(false);
					//12.注册选择器
					clientChannel.register(selector, selectionKey.OP_READ);
				}else if(selectionKey.isReadable()) {
					//13.获取当前选择器上读就绪的状态的通道
					SocketChannel clientChannel = (SocketChannel)selectionKey.channel();
					//14.读取数据
					ByteBuffer buffer = ByteBuffer.allocate(1024);
					int len = 0;
					while((len = clientChannel.read(buffer)) != -1) {
						buffer.flip();
						System.out.println(new String(buffer.array(),0,len));
						buffer.clear();
					}
				}
				//15.取消选择键
				iterator.remove();
			}
		}
		
		
		
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值