关于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. vijos 1655 萌萌的糖果博弈 博弈

    背景 用糖果来引诱小朋友学习是最常用的手法,绵羊爸爸就是用糖果来引诱萌萌学习博弈的. 描述 他把糖果分成了两堆,一堆有A粒,另一堆有B粒.他让萌萌和他一起按照下面的规则取糖果:每次可以任意拿走其中一堆 ...

  2. CODE FESTIVAL 2017 qual B C - 3 Steps

    Score : 500 points Problem Statement Rng has a connected undirected graph with N vertices. Currently ...

  3. idea编写的java代码,在cmd运行乱码解决方案

    1.解决方案 使用txt打开,另存为的时候选择编码为ANSI 即可.

  4. MSSQL 视图/事务(TRAN[SACTION])/存储过程(PROC[EDURE])/触发器(TRIGGER )

    --视图 视图是一张虚拟表,它表示一张表的部分数据或多张表的综合数据,其结构和数据是建立在对表的查询基础上 视图在操作上和数据表没有什么区别,但两者的差异是其本质是不同: 数据表是实际存储记录的地方, ...

  5. bzoj 1188 SG函数

    首先我们可以把一个石子看成一个单独的游戏,那么我们可以发现所有位置的石子至于奇偶有关,因为某一个人操作其中的一个石子,我们可以用相同的石子做相同的操作,所以我们只需要保留下所有位置的01,那么对于每个 ...

  6. vue中的图片加载与显示默认图片

    HTML: <div class="content-show-img"> <div class="show-img"> <img ...

  7. mysql之基本数据库操作(二)

    环境信息 数据库:mysql-5.7.20 操作系统:Ubuntu-16.04.3 mysql的启动.退出.重启 # 启动 $ sudo service mysqld start # 停止 $ sud ...

  8. 前端—css

    css css概述 CSS是Cascading Style Sheets的简称,中文称为层叠样式表,用来控制网页数据的表现,可以使网页的表现与数据内容分离. 一.css的四种引入方式: 1.行内式   ...

  9. 【Python学习笔记】Coursera课程《Python Data Structures》 密歇根大学 Charles Severance——Week6 Tuple课堂笔记

    Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week6 Tuple 10 Tuples 10.1 Tuples A ...

  10. 【常见的SQL Server连接失败错误以及解决方法】

    [常见的SQL Server连接失败错误以及解决方法] http://blog.csdn.net/feixianxxx/article/details/5523922 ADO连接SQL Server ...