浅析Netty的异步事件驱动(二)
上一篇文件浅析了Netty中的事件驱动过程,这篇主要写一下异步相关的东东。
首先,什么是异步了?
异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
异步的好处是不会造成阻塞,在高并发情形下会更稳定和更高的吞吐量。
说到Netty中的异步,就不得不提ChannelFuture。Netty中的IO操作是异步的,包括bind、write、connect等操作会简单的返回一个ChannelFuture,调用者并不能立刻获得结果。
当future对象刚刚创建时,处于非完成状态。可以通过isDone()方法来判断当前操作是否完成。通过isSuccess()判断已完成的当前操作是否成功,getCause()来获取已完成的当前操作失败的原因,isCancelled()来判断已完成的当前操作是否被取消。
调用者可以通过返回的ChannelFuture来获取操作执行的状态,注册监听函数来执行完成后的操作。
其实同步的阻塞和异步的非阻塞可以直接通过代码看出:
这是一段阻塞的代码:
printTime("开始connect: ");
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
// Wait until the connection is closed or the connection attempt fails.
future.getChannel().getCloseFuture().awaitUninterruptibly();
printTime("connect结束: ");
// Shut down thread pools to exit.
bootstrap.releaseExternalResources();
这段代码的输出结果是:
开始connect: 2013-07-17 14:45:28 connect结束: 2013-07-17 14:45:29
很明显的可以看出,connect操作导致整段代码阻塞了大概1秒。
以下这段是异步非阻塞的代码:
printTime("开始connect: ");
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener()
{
public void operationComplete(final ChannelFuture future)
throws Exception
{
printTime("connect结束: ");
}
});
printTime("异步时间: ");
// Shut down thread pools to exit.
bootstrap.releaseExternalResources();
输出结果是:
开始connect: 2013-07-17 14:50:09
异步时间: 2013-07-17 14:50:09
connect结束: 2013-07-17 14:50:09
可以明显的看出,在异步模式下,上面这段代码没有阻塞,在执行connect操作后直接执行到printTime("异步时间: "),随后connect完成,future的监听函数输出connect操作完成。
关于同步的阻塞和异步的非阻塞可以打一个很简单的比方,A向B打电话,通知B做一件事。
在同步模式下,A告诉B做什么什么事,然后A依然拿着电话,等待B做完,才可以做下一件事;
在异步模式下,A告诉B做什么什么事,A挂电话,做自己的事。B做完后,打电话通知A做完了。
如上面代码所显示的,ChannelFuture同时提供了阻塞和非阻塞方法,接下来就简单的分析一下各自是怎么实现的。
阻塞方法是await系列,这些方法要小心翼翼的使用,不可以在handler内调用这些方法,否则会造成死锁。
public ChannelFuture awaitUninterruptibly() {
boolean interrupted = false;
synchronized (this) {
//循环等待到完成
while (!done) {
checkDeadLock();
waiters++;
try {
wait();
} catch (InterruptedException e) {
//不允许中断
interrupted = true;
} finally {
waiters--;
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return this;
}
一个标志位,一个while循环,代码简洁明了。
非阻塞则是添加监听类ChannelFutureListener,通过覆盖ChannelFutureListener的operationComplete执行业务逻辑。
public void addListener(final ChannelFutureListener listener) {
if (listener == null) {
throw new NullPointerException("listener");
}
boolean notifyNow = false;
synchronized (this) {
if (done) {
notifyNow = true;
} else {
if (firstListener == null) {
//listener链表头
firstListener = listener;
} else {
if (otherListeners == null) {
otherListeners = new ArrayList<ChannelFutureListener>(1);
}
//添加到listener链表中,以便操作完成后遍历操作
otherListeners.add(listener);
}
......
if (notifyNow) {
//通知listener进行处理
notifyListener(listener);
}
}
然后当操作完成后直接遍历listener链表,把每个listener取出来执行。以setSuccess为例,如下:
public boolean setSuccess() {
synchronized (this) {
// Allow only once.
if (done) {
return false;
}
done = true;
//唤醒所有等待
if (waiters > 0) {
notifyAll();
}
}
//通知所有listener
notifyListeners();
return true;
}
private void notifyListeners() {
if (firstListener != null) {
//执行listener表头
notifyListener(firstListener);
firstListener = null;
//挨个执行其余的listener
if (otherListeners != null) {
for (ChannelFutureListener l: otherListeners) {
notifyListener(l);
}
otherListeners = null;
}
}
}
其实这部分代码的逻辑很简单,就是注册回调函数,当操作完成后自动调用回调函数,就达到了异步的效果。
浅析Netty的异步事件驱动(二)的更多相关文章
- 浅析Netty的异步事件驱动(一)
本篇文章着重于浅析一下Netty的事件处理流程,Netty版本为netty-3.6.6.Final. Netty定义了非常丰富的事件类型,代表了网络交互的各个阶段.并且当各个阶段发生时,触发相应的事件 ...
- 计算机网络通信TCP/IP协议浅析 网络发展简介(二)
本文对计算机网络通信的原理进行简单的介绍 首先从网络协议分层的概念进行介绍,然后对TCP.IP协议族进行了概念讲解,然后对操作系统关于通信抽象模型进行了简单介绍,最后简单描述了socket 分层的 ...
- Netty 源码(二)NioEventLoop 之 Channel 注册
Netty 源码(二)NioEventLoop 之 Channel 注册 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一 ...
- 一个轻巧高效的多线程c++stream风格异步日志(二)
目录 一个轻巧高效的多线程c++stream风格异步日志(二) 前言 LogFile类 AsyncLogging类 AsyncLogging实现 增加备用缓存 结语 一个轻巧高效的多线程c++stre ...
- PHP下的异步尝试二:初识协程
PHP下的异步尝试系列 如果你还不太了解PHP下的生成器,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify ...
- QT 信号槽 异步事件驱动 单线程 多并发
利用好Qt 模块的异步信号槽,单线程同样可是实现很强悍的的并发能力.应付正常的功能是足够的. 需要注意的是:该模式本质上为 单线程 事件驱动异步模式,所以需要做的事优化你的业务代码构架以应付性能与并发 ...
- suging闲谈-netty 的异步非阻塞IO线程与业务线程分离
前言 surging 对外沉寂了一段时间了,但是作者并没有闲着,而是针对于客户的需要添加了不少功能,也给我带来了不少外快收益, 就比如协议转化,consul 的watcher 机制,JAVA版本,sk ...
- 1.- Netty设计理念-异步和事件驱动
0. 关键点 a). 非阻塞网络调用,异步方法立即返回 b). 选择器(Selector)使得单一线程就可监控很多连接上的事件. <dependency> <groupId>i ...
- netty底层是事件驱动的异步库 但是可以await或者sync(本质是future超时机制)同步返回 但是官方 Prefer addListener(GenericFutureListener) to await()
io.netty.channel 摘自:https://netty.io/4.0/api/io/netty/channel/ChannelFuture.html Interface ChannelFu ...
随机推荐
- 团体程序设计天梯赛-练习集L1-011. A-B
L1-011. A-B 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 本题要求你计算A-B.不过麻烦的是,A和B都是字符串 — ...
- 对JAVA动态代理的理解
叫动态代理就代表着有“静态代理”这回事. 而且,通常“动态”至少听着更NB一点. 关键就在于不明白啥叫“动”,这个得跟“静”比较下. 在我的理解,静态代理得自己声明一个类,实现跟被代理对象同样的接口. ...
- POJ 1061 青蛙的约会(扩展欧几里德)
点我看题目 题意 : 中文题不详述. 思路 : 设经过s步后两青蛙相遇,则必满足(x+m*s)-(y+n*s) = K*L(k = 0,1,2....) 变形得:(n-m)*s+K*L = x-y ; ...
- gcc: error trying to exec 'cc1plus': execvp: 没有该文件或目录 解决方案
一般来说,装完linux系统(ubuntu)后,要自己安装java或者c/c++的环境. 这个提示就是说你的系统缺少 g++ 包. 请执行:sudo apt-get install g++ (在ub ...
- windows8 64位 IIS8 PHP5.5 安装 Imagemagick 组件
为什么这里一定要说 windows 系统是64位呢,因为如果是系统是64位,那么PHP5.5 一般都会选择64的, Imagemagick 组件也会选择64位的, 但是操蛋的是 64位的Imagema ...
- 初始化D3D设备
bool initD3D(HWND hWnd) { // 主要目的是获取设备,为调用下面的函数做很多准备. // 比如 获取IDirect3D9 ,获取支持的顶点处理,填充后备缓冲相关参数等. // ...
- Android开发之Bitmap.Config.RGB_565
在学习xutils框架的时候,看到sample代码中有一行这样的代码: bitmapUtils.configDefaultBitmapConfig(Bitmap.Config.RGB_565); Bi ...
- Grunt 初体验
对于没有接触过类似自动化工具的朋友,对 grunt 也许只是停留在听过阶段,而并没有真正的使用过.今天就从最初级的教程说起.在开始教程之前,需要先确保你已经安装了 node. 下面就开始来讲解 gru ...
- 中南大学oj 1317 Find the max Link 边权可以为负的树上最长路 树形dp 不能两遍dfs
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1317经典问题:树上最长路,边权可以为负值的,树形dp,不能用两边dfs.反例:5 41 2 22 ...
- POJ 2398 Toy Storage
这道题和POJ 2318几乎是一样的. 区别就是输入中坐标不给排序了,=_=|| 输出变成了,有多少个区域中有t个点. #include <cstdio> #include <cma ...