关于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. java线程的3种创建方式及优缺点

    线程创建简介 1.在java中表示线程的是Thread类.无论是那种方式创建线程,本质上都是创建Thread类的对象. 2.Thread类继承Runnable接口,且也有以Runnable作为参数的构 ...

  2. yum快速安装gitlab

    安装gitlab前戏使用官方的源,还是比较慢的,gitlab官方提供了一个清华大学的源 新建 /etc/yum.repos.d/gitlab-ce.repo,内容为 源[gitlab-ce]name= ...

  3. SpringBoot jar包不支持jsp

    官方原文如下: When running a Spring Boot application that uses an embedded servlet container (and is packa ...

  4. 用reduce实现简单的pipe

    function pipe(src, ...fns){ return fns.reduce(function(fn1, fn2){ return fn2(fn1) }, src); } undefin ...

  5. 【BZOJ4491】我也不知道题目名字是什么 [线段树]

    我也不知道题目名字是什么 Time Limit: 10 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 给定一个序列A[i ...

  6. 深入理解微服务架构spring的各个知识点(面试必问知识点)

    什么是spring spring是一个开源框架,spring为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能. Spring是一个轻量级的控制反转 ...

  7. TensorFlow非线性拟合

    1.心得: 在使用TensorFlow做非线性拟合的时候注意的一点就是输出层不能使用激活函数,这样就会把整个区间映射到激活函数的值域范围内无法收敛. # coding:utf-8 import ten ...

  8. bzoj 2733 平衡树启发式合并

    首先对于一个连通块中,询问我们可以直接用平衡树来求出排名,那么我们可以用并查集来维护各个块中的连通情况,对于合并两个平衡树,我们可以暴力的将size小的平衡树中的所有节点删掉,然后加入大的平衡树中,因 ...

  9. Caffe 学习笔记1

    Caffe 学习笔记1 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和 ...

  10. sicily 1001. Fibonacci 2

    1001. Fibonacci 2   Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn-1 + F ...