java nio 是指非阻塞io模式, 采用Reactor 模式实现及Observer模式。当IO通道中有数据进来的时候就会自动通知注册在通道的事件,然后找到对应的事件去执行。
看下面示例
package com.yukh.nio.selector;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Logger;
/**
* 以下代码中巧妙使用了SocketChannel的attach功能,
*将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,
*可以立即触发相应链接的Handler。
*/
public class Reactor implements Runnable {
public static Logger logger = Logger.getLogger(Reactor.class);
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); // 调整此通道的阻塞模式。 - 异步
SelectionKey sk = serverSocket.register(selector, // 向selector注册该channel
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);
}
}
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)
new SocketReadHandler(selector, c); // 调用Handler来处理channel
} catch (IOException ex) {
logger.debug("accept stop!" + ex);
}
}
}
}
处理类
package com.yukh.nio.selector;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import org.apache.log4j.Logger;
public class SocketReadHandler implements Runnable {
public static Logger logger = Logger.getLogger(SocketReadHandler.class);
// private Test test=new Test();
final SocketChannel socket;
final SelectionKey sk;
static final int READING = 0, SENDING = 1;
int state = READING;
public SocketReadHandler(Selector sel, SocketChannel c) throws IOException {
socket = c;
socket.configureBlocking(false);
sk = socket.register(sel, 0);
// 将SelectionKey绑定为本Handler 下一步有事件触发时,将调用本类的run方法。
// 参看dispatch(SelectionKey k)
sk.attach(this);
// 同时将SelectionKey标记为可读,以便读取。
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}
public void run() {
try {
// test.read(socket,input);
readRequest();
} catch (Exception ex) {
logger.debug("readRequest error" + ex);
}
}
/**
* 处理读取data
*
* @param key
* @throws Exception
*/
private void readRequest() throws Exception {
ByteBuffer input = ByteBuffer.allocate(1024);
input.clear();
try {
int bytesRead = socket.read(input);
// 激活线程池 处理这些request
// requestHandle(new Request(socket,btt));
} catch (Exception e) {
}
}
}