java nio实例_java NIO原理及实例

1、reactor(反应器)模式

使用单线程模拟多线程,提高资源利用率和程序的效率,增加系统吞吐量。下面例子比较形象的说明了什么是反应器模式:

一个老板经营一个饭店,

传统模式 - 来一个客人安排一个服务员招呼,客人很满意;(相当于一个连接一个线程)

后来客人越来越多,需要的服务员越来越多,资源条件不足以再请更多的服务员了,传统模式已经不能满足需求。老板之所以为老板自然有过人之处,老板发现,服务员在为客人服务时,当客人点菜的时候,服务员基本处于等待状态,(阻塞线程,不做事)。

于是乎就让服务员在客人点菜的时候,去为其他客人服务,当客人菜点好后再招呼服务员即可。 --反应器(reactor)模式诞生了

饭店的生意红红火火,几个服务员就足以支撑大量的客流量,老板用有限的资源赚了更多的money~~~~^_^

2、NIO中的重要概念 通道、缓冲区、选择器

通道:类似于流,但是可以异步读写数据(流只能同步读写),通道是双向的,(流是单向的),通道的数据总是要先读到一个buffer 或者 从一个buffer写入,即通道与buffer进行数据交互。

通道类型:

FileChannel:从文件中读写数据。

DatagramChannel:能通过UDP读写网络中的数据。

SocketChannel:能通过TCP读写网络中的数据。

ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

FileChannel比较特殊,它可以与通道进行数据交互, 不能切换到非阻塞模式,套接字通道可以切换到非阻塞模式;

缓冲区 - 本质上是一块可以存储数据的内存,被封装成了buffer对象而已!

缓冲区类型:

ByteBuffer

MappedByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

常用方法:

allocate() - 分配一块缓冲区

put() -  向缓冲区写数据

get() - 向缓冲区读数据

filp() - 将缓冲区从写模式切换到读模式

clear() - 从读模式切换到写模式,不会清空数据,但后续写数据会覆盖原来的数据,即使有部分数据没有读,也会被遗忘;

compact() - 从读数据切换到写模式,数据不会被清空,会将所有未读的数据copy到缓冲区头部,后续写数据不会覆盖,而是在这些数据之后写数据

mark() - 对position做出标记,配合reset使用

reset() - 将position置为标记值

缓冲区的一些属性:

capacity - 缓冲区大小,无论是读模式还是写模式,此属性值不会变;

position - 写数据时,position表示当前写的位置,每写一个数据,会向下移动一个数据单元,初始为0;最大为capacity - 1

切换到读模式时,position会被置为0,表示当前读的位置

limit - 写模式下,limit 相当于capacity 表示最多可以写多少数据,切换到读模式时,limit 等于原先的position,表示最多可以读多少数据。

选择器:相当于一个观察者,用来监听通道感兴趣的事件,一个选择器可以绑定多个通道;

通道向选择器注册时,需要指定感兴趣的事件,选择器支持以下事件:

SelectionKey.OP_CONNECT

SelectionKey.OP_ACCEPT

SelectionKey.OP_READ

SelectionKey.OP_WRITE

如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来,如下:

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

通道向选择器注册时,会返回一个 SelectionKey对象,具有如下属性

interest集合

ready集合

Channel

Selector

附加的对象(可选)

用“位与”操作interest 集合和给定的SelectionKey常量,可以确定某个确定的事件是否在interest 集合中。

int interestSet = selectionKey.interestOps();

boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT;

boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;

boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;

boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;

ready 集合是通道已经准备就绪的操作的集合。在一次选择(Selection)之后,你会首先访问这个ready set。Selection将在下一小节进行解释。可以这样访问ready集合:

int readySet = selectionKey.readyOps();

也可以使用以下四个方法获取已就绪事件,返回值为boolean:

selectionKey.isAcceptable();

selectionKey.isConnectable();

selectionKey.isReadable();

selectionKey.isWritable();

可以将一个对象或者更多信息附着到SelectionKey上,即记录在附加对象上,方法如下:

selectionKey.attach(theObject);

Object attachedObj = selectionKey.attachment();

可以通过选择器的select方法获取是否有就绪的通道;

int select()

int select(long timeout)

int selectNow()

返回值表示上次执行select之后,就绪通道的个数。

可以通过selectedKeySet获取已就绪的通道。返回值是SelectionKey 的集合,处理完相应的通道之后,需要removed因为Selector不会自己removed

select阻塞后,可以用wakeup唤醒;执行wakeup时,如果没有阻塞的select  那么执行完wakeup后下一个执行select就会立即返回。

调用close() 方法关闭selector

下面是一个简单的实例代码,帮助理解上面的内容:

8f900a89c6347c561fdf2122f13be562.png NIO服务器端

8f900a89c6347c561fdf2122f13be562.png BIO服务器端

8f900a89c6347c561fdf2122f13be562.png BIO客户端及测试类

其中 testNioServer()方法,是启动NIO服务器端;

testBioServer()方法是启动BIO服务器端

testConnect()是BIO的一个连接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值