100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > java实现非阻塞io原理_JAVA 非阻塞IO原理

java实现非阻塞io原理_JAVA 非阻塞IO原理

时间:2023-12-15 13:35:54

相关推荐

java实现非阻塞io原理_JAVA 非阻塞IO原理

1. 基本概念

IO是主存和外部设备(硬盘、终端和网络等)传输数据的过程。IO是操作系统的底层功能实现,底层通过I/O指令进行完成。

2.nio简介 nio是java New IO的简称(并不只是指非阻塞IO),在jdk1.4里提供的新api。Sun官方标榜的特性如下:

– 为所有的原始类型提供(Buffer)缓存支持。

– 字符集编码解码解决方案。

– Channel:一个新的原始I/O抽象。

– 支持锁和内存映射文件的文件访问接口。

– 提供多路(non-bloking)非阻塞式的高伸缩性网络I/O。

详细介绍可见 /topic/834447

3.非阻塞 IO

何为阻塞、何为非阻塞,非阻塞原理。

何为阻塞?

一个常见的网络IO通讯流程如下:

何为非阻塞?

下面有个隐喻:

一辆从 A 开往 B 的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好?

1. 司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。 ( 类似阻塞式 )

2. 每个人告诉售票员自己的目的地,然后睡觉,司机只和售票员交互,到了某个点由售票员通知乘客下车。 ( 类似非阻塞 )

很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是 CPU 。在阻塞式里面,每个线程需要不断的轮询,上下文切换,以达到找到目的地的结果。而在非阻塞方式里,每个乘客 ( 线程 ) 都在睡觉 ( 休眠 ) ,只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。

socket的操作都有一个共同的结构:

1. Read request

2. Decode request

3. Process service

4. Encode reply

5. Send reply

经典的网络服务的设计如下图,在每个线程中完成对数据的处理:

但这种模式在用户负载增加时,性能将下降非常的快。我们需要重新寻找一个新的方案,保持数据处理的流畅,很显然,事件触发机制是最好的解决办法,当有事件发生时,会触动handler,然后开始数据的处理。 Reactor模式类似于AWT中的Event处理:

Reactor模式参与者

1.Reactor 负责响应IO事件,一旦发生,广播发送给相应的Handler去处理,这类似于AWT的thread

2.Handler 是负责非堵塞行为,类似于AWT ActionListeners;同时负责将handlers与event事件绑定,类似于AWT addActionListener

非阻塞的原理

把整个过程切换成小的任务,通过任务间协作完成。

由一个专门的线程来处理所有的 IO 事件,并负责分发

事件驱动机制:事件到的时候触发,而不是同步的去监视事件。

线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少无谓的进程切换。

Reactor就是上面隐喻的售票员角色。每个线程的处理流程大概都是读取数据、解码、计算处理、编码、发送响应

如图:

Java的NIO为reactor模式提供了实现的基础机制,它的Selector当发现某个channel有数据时,会通过SlectorKey来告知我们,在此我们实现事件和handler的绑定。

我们来看看Reactor模式代码:

public class Reactor implements Runnable{

final Selector selector;

final ServerSocketChannel serverSocket;

Reactor(int port) throws IOException {

selector = Selector.open();

serverSocket = ServerSocketChannel.open();

InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(),port);

serverSocket.socket().bind(address);

serverSocket.configureBlocking(false);

//向selector注册该channel

SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT);

logger.debug("-->Start serverSocket.register!");

//利用sk的attache功能绑定Acceptor 如果有事情,触发Acceptor

sk.attach(new Acceptor());

logger.debug("-->attach(new Acceptor()!");

}

public void run() { // normally in a new Thread

try {

while (!Thread.interrupted())

{

selector.select();

Set selected = selector.selectedKeys();

Iterator it = selected.iterator();

//Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。

while (it.hasNext())

//来一个事件 第一次触发一个accepter线程

//以后触发SocketReadHandler

dispatch((SelectionKey)(it.next()));

selected.clear();

}

}catch (IOException ex) {

logger.debug("reactor stop!"+ex);

}

}

//运行Acceptor或SocketReadHandler

void dispatch(SelectionKey k) {

Runnable r = (Runnable)(k.attachment());

if (r != null){

// r.run();

}

}

class Acceptor implements Runnable { // inner

public void run() {

try {

logger.debug("-->ready for accept!");

SocketChannel c = serverSocket.accept();

if (c != null)

//调用Handler来处理channel

new SocketReadHandler(selector, c);

}

catch(IOException ex) {

logger.debug("accept stop!"+ex);

}

}

}

}

以上代码中巧妙使用了SocketChannel的attach功能,将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,可以立即触发相应链接的Handler。

将数据读出后,可以将这些数据处理线程做成一个线程池,这样,数据读出后,立即扔到线程池中,这样加速处理速度:

可参考:

/concurrent/reactor.htm

/blog/221641

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。