关于Reactor模式,不再多做介绍,推荐Doug Lea大神的教程:Java 可扩展的IO

本来在Reactor的构造方法中完成一系列操作是没有问题的:

public class Reactor implements Runnable {

    private final Selector selector;

    public Reactor() throws IOException {
selector = Selector.open();
String host = "127.0.0.1";
int port = 12345;
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(host, port));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT, new Acceptor(serverChannel, selector));
} @Override
public void run() {
while (!Thread.interrupted()) {
try {
selector.select();
Set<SelectionKey> selected = selector.selectedKeys();
Iterator<SelectionKey> it = selected.iterator();
while (it.hasNext()) {
dispatch(it.next());
}
selected.clear();
} catch (IOException e) {
e.printStackTrace();
}
}
} private void dispatch(SelectionKey next) {
Runnable r = (Runnable) next.attachment();
if (r != null) {
r.run();
}
} public void registerChannel(SelectableChannel channel, int ops) throws IOException {
if (channel instanceof ServerSocketChannel) {
ServerSocketChannel socketChannel = (ServerSocketChannel) channel;
channel.register(selector, ops, new Acceptor(socketChannel, selector));
}
}
}

然而有些参数需要在外层操作,我想这样弄:

public Reactor() throws IOException {
selector = Selector.open();
}

在主线程中启动server [reactorManager.start()来启动Reactor线程]

private void startReactorManager() throws IOException {
reactorManager = new ReactorManager();
reactorManager.start();
} private void startNIOServer(ServerConfig serverConfig) throws IOException {
String host = serverConfig.getHost();
int port = serverConfig.getTcpPort();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(host, port));
serverChannel.configureBlocking(false);
reactorManager.registerChannel(serverChannel, SelectionKey.OP_ACCEPT);
}

也就是先启动一个线程来Selector.open();然后在主线程中注册通道和事件。

结果一直无法监听到客户端的连接,跟踪才发现服务端的注册方法阻塞了,原因是锁的问题,具体还不清楚。

这里留下一个疑问

想一想,既然在构造函数中可以注册,放到main线程中却不行,那么是否我们可以在注册时检查,如果this是当前Reactor线程,就直接注册,这跟在构造函数中没有区别。

如果不是,就放到队列中,当然你这时放了,selector.select()一直阻塞着,你也无法取出来注册,那么我们可以利用selector.wakeup()唤醒它。

新的方案如下:

public class Reactor extends Thread {

    private final Selector selector;
private LinkedBlockingQueue<Object[]> register = new LinkedBlockingQueue<>() ;//channel、ops、attach
private final AtomicBoolean wakeup = new AtomicBoolean() ; public Reactor() throws IOException {
selector = Selector.open();
} @Override
public void run() {
while (!Thread.interrupted()) {
try {
wakeup.set(false);
processRegister();
selector.select();
Set<SelectionKey> selected = selector.selectedKeys();
Iterator<SelectionKey> it = selected.iterator();
while (it.hasNext()) {
dispatch(it.next());
}
selected.clear();
} catch (IOException e) {
e.printStackTrace();
}
}
} private void processRegister() {
Object[] object;
while ((object = this.register.poll()) != null) {
try {
SelectableChannel channel = (SelectableChannel) object[0];
if (!channel.isOpen())
continue;
int ops = ((Integer) object[1]).intValue();
Object attachment = object[2];
channel.register(this.selector, ops, attachment);
} catch (Exception e) {
e.printStackTrace();
}
}
} private void dispatch(SelectionKey next) {
Runnable r = (Runnable) next.attachment();
if (r != null) {
r.run();
}
} public void registerChannel(SelectableChannel channel, int ops) throws IOException {
ServerSocketChannel serverChannel = null;
if (channel instanceof ServerSocketChannel) {
serverChannel = (ServerSocketChannel) channel;
}
Object attachment = new Acceptor(serverChannel, selector);
if (this == Thread.currentThread()) {
serverChannel.register(selector, ops, attachment);
} else {
this.register.offer(new Object[]{ channel, ops, attachment });
if (wakeup.compareAndSet(false, true)) {
this.selector.wakeup();
}
}
}
}

这样就解决了问题,在此记录下!

NIO使用Reactor模式遇到的问题的更多相关文章

  1. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...

  2. nio的reactor模式

    转自:http://blog.csdn.net/it_man/article/details/38417761 线程状态转换图 就是非阻塞IO 采用多路分发方式举个例子吧,你服务器做一个聊天室,按照以 ...

  3. NIO及Reactor模式

    关于Nio Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO. Nio要去解决的问题 N ...

  4. Java进阶知识点5:服务端高并发的基石 - NIO与Reactor模式以及AIO与Proactor模式

    一.背景 要提升服务器的并发处理能力,通常有两大方向的思路. 1.系统架构层面.比如负载均衡.多级缓存.单元化部署等等. 2.单节点优化层面.比如修复代码级别的性能Bug.JVM参数调优.IO优化等等 ...

  5. Java I/O模型从BIO到NIO和Reactor模式(转)

    原创文章,转载请务必将下面这段话置于文章开头处(保留超链接).本文转发自技术世界,原文链接 http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 ...

  6. 原生JDK网络编程- NIO之Reactor模式

    “反应”器名字中”反应“的由来: “反应”即“倒置”,“控制逆转”,具体事件处理程序不调用反应器,而向反应器注册一个事件处理器,表示自己对某些事件感兴趣,有时间来了,具体事件处理程序通过事件处理器对某 ...

  7. 【死磕 NIO】— Reactor 模式就一定意味着高性能吗?

    大家好,我是大明哥,我又来了. 为什么是 Reactor 一般所有的网络服务,一般分为如下几个步骤: 读请求(read request) 读解析(read decode) 处理程序(process s ...

  8. 知识联结梳理 : I/O多路复用、EPOLL(SELECT/POLL)、NIO、Event-driven、Reactor模式

    为了形成一个完整清晰的认识,将概念和关系梳理出来,把坑填平. I/O多路复用 I/O多路复用主要解决传统I/O单线程阻塞的问题.它通过单线程管理多个FD,当监听的FD有状态变化的时候的,调用回调函数, ...

  9. Reactor模式和NIO(转载二)

    本文可看成是对Doug Lea Scalable IO in Java一文的翻译. 当前分布式计算 Web Services盛行天下,这些网络服务的底层都离不开对socket的操作.他们都有一个共同的 ...

随机推荐

  1. git概论

    感谢:http://www.cnblogs.com/atyou/archive/2013/03/11/2953579.html git,一个非常强大的版本管理工具.Github则是一个基于Git的日益 ...

  2. 好用的python库(转)

    这个专区就是用来分享你在使用 Python 过程中发现的或者自己写的 Python 库.有时候一个好用的库将大大节省一个开发者的时间,也会让开发者多这个库的作者感激涕零的.例如我在开发 Pythonz ...

  3. websocket连接相关的几个问题

    https://blog.csdn.net/shangmingtao/article/details/75810099 https://blog.csdn.net/keketrtr/article/d ...

  4. XAMPP 启动mysql报错 InnoDB: Error: could not open single-table tablespace file……

    昨天安装了最新版本XAMPP for Windows 1.8.3. 今天早上打开XAMPP双击mysql Start按钮报错,如下(部分截取): 2013-09-17 10:12:02 9012 [E ...

  5. bootstrap框架的搭建

    bootstrap框架 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快 ...

  6. NGINX: 配置 HSTS

    参考: [ 浅析 HSTS - 博客园 ] [ HTTP HSTS协议和 nginx - 运维生存时间] [ HSTS ] Header: Strict-Transport-Security Stri ...

  7. Zabbix 通过 JMX 监控 java 进程

    参考: [ JMX monitoring ] [ Zabbix Java gateway ] [ JMX Monitoring (Java Gateway) not Working ] [ Monit ...

  8. 【洛谷 P5110】 块速递推(矩阵加速,分块打表)

    题目链接 掌握了分块打表法了.原来以前一直想错了... 块的大小\(size=\sqrt n\),每隔\(size\)个数打一个表,还要在\(0\text{~}size-1\)每个数打一个表. 然后就 ...

  9. 2008 APAC local onsites C Millionaire (动态规划,离散化思想)

    Problem You have been invited to the popular TV show "Would you like to be a millionaire?" ...

  10. 一键前端代理,一行命令开启nginx容器,代理前端页面

    我们在前端开发的过程中,在对接口时候,往往需要跨域请求,那么及其简便的方法就是使用nginx反向代理,但是存在几点缺点 1.在新的一个项目下,我们需要找到安装nginx目录的nginx.conf文件并 ...